12

そのため、ファイル データを を受け取る API にフィードしていますReader。進行状況を報告する方法が必要です。

FilterInputStreamをラップしFileInputStream、読み取ったバイト数とファイルの合計サイズを追跡し、一部のupdate()進行状況を報告するために何らかのイベントを発生させる (または何らかのメソッドを呼び出す)実装を作成するのは簡単なようです。

(あるいは、読み取った絶対バイト数を報告し、他の誰かが計算を行うこともできます。他のストリーミング状況では、より一般的に役立つかもしれません。)

私はこれを以前に見たことがあり、以前に行ったことがあるかもしれませんが、コードを見つけることができず、怠け者です。誰かがそれを敷設しましたか?または、誰かがより良いアプローチを提案できますか?


1年(と少し)後…

以下のAdamskiの回答に基づいて解決策を実装しましたが、うまくいきましたが、数か月使用した後はお勧めしません. 更新が多い場合、不要な進捗イベントの発生/処理は莫大なコストになります。基本的なカウント メカニズムは問題ありませんが、プログレス ポーリングを気にかけている人は、プログレス ポーリングをプッシュするよりもはるかに優れています。

(合計サイズがわかっている場合は、1% を超える変化ごとにイベントを発生させるなどの方法を試すことができますが、実際には問題を起こす価値はありません。多くの場合、そうではありません。)

4

5 に答える 5

6

Guavacom.google.common.ioパッケージが少し役に立ちます。以下はコンパイルもテストもされていませんが、正しい方向に進むはずです。

long total = file1.length();
long progress = 0;
final OutputStream out = new FileOutputStream(file2);
boolean success = false;
try {
  ByteStreams.readBytes(Files.newInputStreamSupplier(file1),
      new ByteProcessor<Void>() {
        public boolean processBytes(byte[] buffer, int offset, int length)
            throws IOException {
          out.write(buffer, offset, length);
          progress += length;
          updateProgressBar((double) progress / total);
          // or only update it periodically, if you prefer
        }
        public Void getResult() {
          return null;
        }
      });
  success = true;
} finally {
  Closeables.close(out, !success);
}

これは多くのコードのように見えるかもしれませんが、最小限のコードで済むと思います。(この質問に対する他の回答では完全なコード例が提供されていないため、そのように比較するのは難しいことに注意してください。)

于 2010-05-25T20:42:31.297 に答える
5

Adamski による回答は機能しますが、小さなバグがあります。オーバーライドされたメソッドは、スーパー クラスを介してread(byte[] b)メソッドを呼び出します。 Soは読み取りアクションごとに 2 回呼び出され、ファイル全体が読み取られた後、ファイルのサイズの 2 倍の になります。read(byte[] b, int off, int len)
updateProgress(long numBytesRead)numBytesRead

メソッドをオーバーライドしないread(byte[] b)と、問題が解決します。

于 2010-12-10T14:13:31.610 に答える
1

GUIアプリケーションを構築している場合は、常にProgressMonitorInputStreamがあります。説明する方法でGUIをラップするInputStream必要がない場合は、ここに質問を投稿するよりも簡単で時間もかかりません。

于 2009-08-27T07:49:31.563 に答える
0

@Kevin Bourillion によって与えられた回答を完了するには、この手法を使用してネットワーク コンテンツにも適用できます (ストリームを 2 回読み取ることを防ぎます: 1 つはサイズ用、もう 1 つはコンテンツ用です)。

        final HttpURLConnection httpURLConnection = (HttpURLConnection) new URL( url ).openConnection();
        InputSupplier< InputStream > supplier = new InputSupplier< InputStream >() {

            public InputStream getInput() throws IOException {
                return httpURLConnection.getInputStream();
            }
        };
        long total = httpURLConnection.getContentLength();
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ByteStreams.readBytes( supplier, new ProgressByteProcessor( bos, total ) );

ProgressByteProcessor は内部クラスです。

public class ProgressByteProcessor implements ByteProcessor< Void > {

    private OutputStream bos;
    private long progress;
    private long total;

    public ProgressByteProcessor( OutputStream bos, long total ) {
        this.bos = bos;
        this.total = total;
    }

    public boolean processBytes( byte[] buffer, int offset, int length ) throws IOException {
        bos.write( buffer, offset, length );
        progress += length - offset;
        publishProgress( (float) progress / total );
        return true;
    }

    public Void getResult() {
        return null;
    }
}
于 2012-10-11T13:58:04.353 に答える