Как отслеживать прогресс (JProgressBar) с помощью метода FileChannels TransferFrom ()? - PullRequest
14 голосов
/ 15 февраля 2010

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

У меня сейчас два вопроса.

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

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

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

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

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

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

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

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

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


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

Ответы [ 3 ]

27 голосов
/ 17 июня 2012

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

Если вы хотите следить за прогрессом, это лучше, так как 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;
        }
    }
}
7 голосов
/ 15 февраля 2010

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

2 голосов
/ 15 февраля 2010

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

...