15

コンポーネントについて少し助けが必要JProgressBarです。私のプログラムは、を使用してファイルをある場所から別の場所にコピーしますjava.nio FileChannels。実際のコピー方法はtransferFrom().

今2つ質問があります。

  1. FileChannel の転送の進行状況を監視するにはどうすればよいですか? 私が見つけたすべてのチュートリアルは、従来の java.io InputStreams を使用し、inputstream をループしながら進行状況 int を増やします。

  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 のままであり、その理由はわかりません。何か不足していますか?

ありがとうございます!ご意見をお待ちしております。1 つのファイルの進行状況の監視が機能するようになったので、2 つ目の問題に取り組みましょう。


1 つのファイルだけでなく、多数のファイルの進行状況を監視したいのですが、その必要はありません。私の主なコピー メソッドは、さまざまなディレクトリを繰り返し処理し、実際の転送メソッドを呼び出して適切なファイルをコピーします。したがって、コピー方法はファイルを転送しません。実際の転送方法でファイルを選択しているだけです。

4

3 に答える 3

28

ここで非常に古いスレッドを復活させていることに気付きましたが、今日グーグルで見つけたので...

進行状況を監視したい場合は、転送を最適化できるように、システムにチャンク サイズを処理させることを 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://example.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();
            } 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;
        }
    }
}
于 2012-06-17T01:50:52.617 に答える
7

の単一の呼び出しの進行状況を監視する方法はありませんがtransferFrom、オフセットと長さのパラメーターを渡すことができるため、独自のループを実装して、適切なサイズのデータ​​ チャンク間で進行状況バーを更新できます。

于 2010-02-14T22:41:12.790 に答える
2

transferTo()...それは、そもそも、コピーを可能な限りカーネルに渡すという使用のポイントを完全に超えているでしょうが。あなたはそれをしたいのか、あなたは進歩を見たいのか。あなたが選択する必要があります。少なくとも、進行状況の表示で必要な粒度を選択する必要があります。

于 2010-02-15T00:07:26.770 に答える