4

を使用してZipOutputStream、既に圧縮された形式と、プレーンテキストのような圧縮性の高い多くの大きな形式が混在する一連のファイルを圧縮しています。

すでに圧縮された形式のほとんどは大きなファイルであり、再圧縮に CPU とメモリを費やすことは意味がありません。

.setMethod(ZipEntry.STORED)事前に圧縮されたファイルを検出したときに使用しようとしていますがsize, compressedSize and crc、それらのファイルに を提供する必要があると不平を言っています。

次のアプローチで動作させることができますが、これにはファイルを 2 回読み取る必要があります。を計算してCRC32から、実際にファイルを にコピーしますZipOutputStream

// code that determines the value of method omitted for brevity
if (STORED == method)
{
    fze.setMethod(STORED);
    fze.setCompressedSize(fe.attributes.size());
    final HashingInputStream his = new HashingInputStream(Hashing.crc32(), fis);
    ByteStreams.copy(his,ByteStreams.nullOutputStream());
    fze.setCrc(his.hash().padToLong());
}
else
{
    fze.setMethod(DEFLATED);
}
zos.putNextEntry(fze);
ByteStreams.copy(new FileInputStream(fe.path.toFile()), zos);
zos.closeEntry();

入力ストリームを 2 回読み取ることなく、この情報を提供する方法はありますか?

4

1 に答える 1

1

簡潔な答え:

CRCこの問題を解決するために必要な時間を考えると、ファイルを 1 回だけ読み取り、標準ライブラリを使用してを計算する方法を特定できませんでした。

50%平均して時間を短縮する最適化を見つけました。

制限付きCRCで同時に保存されるファイルの数を事前に計算し、それらが完了するまで待ちます。この効果は、計算が必要なファイルの数によって異なります。ファイルが多いほど、メリットが大きくなります。ExecutorCompletionServiceRuntime.getRuntime().availableProcessors()CRC

次に、一時的に実行されているペアから aを.postVisitDirectories()ラップしてを に変換し、に渡して、事前計算されたすべてのオブジェクトをシリアルに書き込みながら、の結果をリモート サーバーにアップロードします。ZipOutputStreamPipedOutputStreamPipedInputStream/PipedOutputStreamThreadZipOutputStreamInputStreamHttpRequestZipOutputStreamZipEntry/Path

300+GB今のところ、差し迫ったニーズを処理するにはこれで十分ですが、10TB仕事に着いたら、それに対処し、複雑になりすぎずにいくつかの利点を見つけようとします.

時間的にかなり良いものを思いついた場合は、この回答を新しい実装で更新します。

長い答え:

ZipOutputStreamマルチパートzipファイル、インテリジェントな圧縮レベルvsをサポートするクリーンルームを作成することになり、ストリームの最後にメタデータを読み込んで書き出すときSTOREに計算することができました.CRC


ZipOutputStream.setLevel() スワッピングが機能しない理由:

ZipOutputStream.setLevel(NO_COMPRESSION/DEFAULT_COMPRESSION) ハックは実行可能なアプローチではありません。数百ギガのデータ、数千のフォルダーとファイルに対して広範なテストを行い、測定値は決定的でした. CRCファイルのを 計算するよりもSTOREDで圧縮するよりも何も得られませんNO_COMPRESSION。実際には 大幅に遅くなります!

私のテストでは、ファイルはネットワークにマウントされたドライブ上にあるため、既に圧縮されているファイルをネットワーク経由で2 回読み取ってを計算しCRC、再度 に追加するのは、すべてのファイルを 1 回処理して を変更するZipOutputStreamよりも高速でした。DEFLATED.setLevel()ZipOutputStream

ネットワーク アクセスで実行されるローカル ファイルシステム キャッシュはありません。これは最悪のシナリオです。ローカル ファイルシステムのキャッシュにより、ローカル ディスク上のファイルの処理がはるかに高速になります。

したがって、このハックは単純なアプローチであり、誤った仮定に基づいています。レベルでも圧縮アルゴリズムを介してデータを処理しているためNO_COMPRESSION、ファイルを 2 回読み取るよりもオーバーヘッドが高くなります。

于 2016-02-03T23:06:41.057 に答える