Как отслеживать прогресс (JProgressBar) с помощью метода передачи FileChannelsFrom()?

Мне нужна небольшая помощь с компонентом JProgressBar. Моя программа копирует файлы из одного места в другое с помощью java.nio FileChannels. Фактический метод копирования - transferFrom().

У меня есть два вопроса.

  • Как контролировать ход передачи файлов FileChannels? Все обучающие программы, которые я нашел, используют обычные java.io InputStreams и увеличивают прогресс int во время цикла через входной поток.

  • Мои методы копирования (методы FileChannel) инкапсулируются в отдельный метод, который вызывается другими методами, которые перебирают исходные и целевые папки, а затем вызывают методы FileChannel для каждого файла.

Как реализовать ProgressBar для полного механизма копирования?

Ну, я должен был прочитать FAQ немного раньше, поэтому, я думаю, мне нужно отредактировать начальную запись вместо того, чтобы комментировать ответы, правильно?

Хорошо, это то, что я сделал до сих пор. Так же, как предложил jambjo (спасибо, кстати), метод transferFrom() теперь зациклирован. BTW: Есть ли предпочтительный размер фрагмента или зависит от детализации моего индикатора выполнения, как сказал EJP?

Вот мой фрагмент кода:

while (position < size) {
 position += destination.transferFrom(source, position, chunkSize);
 current =  (position/size)*100;
 System.out.println(current);
}

К сожалению, "текущее" значение остается 0 внутри цикла, и я понятия не имею, почему. Я что-то пропустил?

Еще раз спасибо jambjo! Я очень ценю ваш вклад! Теперь, когда мониторинг прогресса одного файла работает, позвольте мне решить мою вторую проблему.


Я бы хотел, я не должен, следить за ходом не только одного файла, но скорее всего нескольких файлов. Мои основные методы копирования повторяются через различные каталоги и копируют соответствующие файлы, вызывая фактический метод передачи. Поэтому методы копирования не передают файлы, они просто выбирают файлы для фактического метода передачи.

Ответы

Ответ 1

Нет способа отслеживать ход одного вызова transferFrom, но поскольку вы можете передавать его параметры смещения и длины, вы можете реализовать свой собственный цикл вокруг него и обновить индикатор выполнения между подходящими размерами блоков данных.

Ответ 2

Я понимаю, что я воскрешаю очень старую нить, но сегодня я нашел ее в своем googling, поэтому...

Если вы хотите отслеживать прогресс, лучше, поскольку EJP предлагает разрешить системе обрабатывать размер блока, чтобы он мог оптимизировать передачу. Способ мониторинга - написать класс-оболочку для ReadableByteChannel, который вы используете для передачи сообщений о выполнении всякий раз, когда вызывается метод read. Вот пример:

package download.progress.example;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

public class DownloadProgressExample {
    public static void main( String[] args ) {
        new Downloader( "/tmp/foo.mp3", "http://foo.com/bar.mp3" );
    }

    private interface RBCWrapperDelegate {
        // The RBCWrapperDelegate receives rbcProgressCallback() messages
        // from the read loop.  It is passed the progress as a percentage
        // if known, or -1.0 to indicate indeterminate progress.
        // 
        // This callback hangs the read loop so a smart implementation will
        // spend the least amount of time possible here before returning.
        // 
        // One possible implementation is to push the progress message
        // atomically onto a queue managed by a secondary thread then
        // wake that thread up.  The queue manager thread then updates
        // the user interface progress bar.  This lets the read loop
        // continue as fast as possible.
        public void rbcProgressCallback( RBCWrapper rbc, double progress );
    }

    private static final class Downloader implements RBCWrapperDelegate {
        public Downloader( String localPath, String remoteURL ) {
            FileOutputStream        fos;
            ReadableByteChannel     rbc;
            URL                     url;

            try {
                url = new URL( remoteURL );
                rbc = new RBCWrapper( Channels.newChannel( url.openStream() ), contentLength( url ), this );
                fos = new FileOutputStream( localPath );
                fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE );
            } catch ( Exception e ) {
                System.err.println( "Uh oh: " + e.getMessage() );
            }
        }

        public void rbcProgressCallback( RBCWrapper rbc, double progress ) {
            System.out.println( String.format( "download progress %d bytes received, %.02f%%", rbc.getReadSoFar(), progress ) );
        }

        private int contentLength( URL url ) {
            HttpURLConnection           connection;
            int                         contentLength = -1;

            try {
                HttpURLConnection.setFollowRedirects( false );

                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod( "HEAD" );

                contentLength = connection.getContentLength();
                connection.disconnect();
            } catch ( Exception e ) { }

            return contentLength;
        }
    }

    private static final class RBCWrapper implements ReadableByteChannel {
        private RBCWrapperDelegate              delegate;
        private long                            expectedSize;
        private ReadableByteChannel             rbc;
        private long                            readSoFar;

        RBCWrapper( ReadableByteChannel rbc, long expectedSize, RBCWrapperDelegate delegate ) {
            this.delegate = delegate;
            this.expectedSize = expectedSize;
            this.rbc = rbc;
        }

        public void close() throws IOException { rbc.close(); }
        public long getReadSoFar() { return readSoFar; }
        public boolean isOpen() { return rbc.isOpen(); }

        public int read( ByteBuffer bb ) throws IOException {
            int                     n;
            double                  progress;

            if ( ( n = rbc.read( bb ) ) > 0 ) {
                readSoFar += n;
                progress = expectedSize > 0 ? (double) readSoFar / (double) expectedSize * 100.0 : -1.0;
                delegate.rbcProgressCallback( this, progress );
            }

            return n;
        }
    }
}

Ответ 3

... хотя это было бы полностью в стороне от использования transferTo(), в первую очередь, чтобы как можно больше копировать ядро ​​в ядро. Либо вы хотите это сделать, либо хотите увидеть прогресс. Вы должны выбрать. По крайней мере, вам нужно выбрать, какую степень детализации вы хотите на индикаторе прогресса.