30

誰かが私が次のようなことをすべきかどうかを勧めることができますか?

os = new GzipOutputStream(new BufferedOutputStream(...));

また

os = new BufferedOutputStream(new GzipOutputStream(...));

どちらがより効率的ですか?BufferedOutputStreamを使用する必要がありますか?

4

6 に答える 6

30

どの順序を使用すればよいですGzipOutputStreamBufferedOutputStream

オブジェクトストリームの場合、入力と出力の両方でバッファリングされたストリームをgzipストリームにラップする方が、ほとんどの場合大幅に高速であることがわかりました。オブジェクトが小さいほど、これはうまくいきました。すべての場合において、バッファリングされたストリームがない場合は、より良いか同じです。

ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis)));
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));

ただし、テキストストリームとストレートバイトストリームの場合、それはトスアップであることがわかりました。バッファリングされたストリームの周りのgzipストリームの方がわずかに優れています。ただし、すべての場合において、バッファリングされたストリームがない方がよいでしょう。

reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis)));
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos)));

各バージョンを20回実行し、最初の実行を中断して、残りを平均しました。また、buffered-gzip-bufferedを試しました。これは、オブジェクトにはわずかに優れており、テキストには劣っています。私はバッファサイズでまったく遊んでいませんでした。


オブジェクトストリームについては、数十メガバイトの2つのシリアル化されたオブジェクトファイルをテストしました。より大きなファイル(38mb)の場合、読み取りでは85%高速(0.7秒対5.6秒)でしたが、実際には書き込みではわずかに低速でした(5.9秒対5.7秒)。これらのオブジェクトにはいくつかの大きな配列が含まれていたため、書き込みが大きくなった可能性があります。

method       crc     date  time    compressed    uncompressed  ratio
defla   eb338650   May 19 16:59      14027543        38366001  63.4%

小さいファイル(18MB)の場合、読み取りが75%高速(1.6秒対6.1秒)、書き込みが40%高速(2.8秒対4.7秒)でした。そこにはたくさんの小さな物体が含まれていました。

method       crc     date  time    compressed    uncompressed  ratio
defla   92c9d529   May 19 16:56       6676006        17890857  62.7%

テキストリーダー/ライターには、64MBのcsvテキストファイルを使用しました。バッファリングされたストリームの周りのgzipストリームは、読み取り時に11%速く(950ミリ秒対1070ミリ秒)、書き込み時にわずかに速くなりました(7.9秒対8.1秒)。

method       crc     date  time    compressed    uncompressed  ratio
defla   c6b72e34   May 20 09:16      22560860        63465800  64.5%
于 2011-05-19T22:12:38.683 に答える
30

GZIPOutputStreamには、すでに組み込みのバッファーが付属しています。したがって、チェーン内でBufferedOutputStreamをそのすぐ隣に配置する必要はありません。gojomoの優れた答えは、バッファーを配置する場所に関するガイダンスをすでに提供しています。

GZIPOutputStreamのデフォルトのバッファーサイズはわずか512バイトであるため、コンストラクターパラメーターを使用して8Kまたは64Kに増やす必要があります。BufferedOutputStreamのデフォルトのバッファーサイズは8Kです。これが、デフォルトのGZIPOutputStreamとBufferedOutputStreamを組み合わせた場合の利点を測定できる理由です。この利点は、GZIPOutputStreamの組み込みバッファーのサイズを適切に設定することでも実現できます。

それで、あなたの質問に答えるために:「私はBufferedOutputStreamを使うべきですか?」→いいえ、あなたの場合、それを使用するべきではありませんが、代わりにGZIPOutputStreamのバッファを少なくとも8Kに設定してください。

于 2013-09-26T15:30:12.120 に答える
12

バッファリングは、データの最終的な宛先が、コードがプッシュするよりも大きなチャンクで最適に読み取り/書き込みされる場合に役立ちます。したがって、一般的には、バッファリングをより大きなチャンクが必要な場所にできるだけ近づける必要があります。あなたの例では、それは省略された「...」なので、BufferedOutputStreamをGzipOutputStreamでラップします。また、BufferedOutputStreamのバッファーサイズを調整して、テストの結果が宛先で最適に機能することを示します。

明示的なバッファリングがない場合でも、外部のBufferedOutputStreamが大いに役立つとは思えません。なぜだめですか?GzipOutputStreamは、外部バッファリングが存在するかどうかに関係なく、同じサイズのチャンクで「...」にwrite()を実行します。したがって、「...」を最適化することはできません。GzipOutputStream write()のサイズに固執しています。

また、非圧縮データではなく圧縮データをバッファリングすることで、メモリをより効率的に使用していることにも注意してください。データが6倍の圧縮を達成することが多い場合、「内部」バッファは「外部」バッファの6倍の大きさに相当します。

于 2009-07-04T22:49:38.000 に答える
4

通常、OSへの呼び出しが多すぎたり、ディスクに頻繁にアクセスしたりしないように、FileOutputStreamの近くにバッファが必要です(これが...を表すと仮定します)。ただし、GZIPOutputStreamに多数の小さなチャンクを書き込んでいる場合は、GZIPOSの周りのバッファーからも恩恵を受ける可能性があります。GZIPOSのwriteメソッドが同期されている理由は、同期されており、他のいくつかの同期呼び出しといくつかのネイティブ(JNI)呼び出し(CRC32を更新して実際の圧縮を行うため)にもつながります。これらはすべて、呼び出しごとに余分なオーバーヘッドを追加します。したがって、その場合は、両方のバッファーの恩恵を受けると思います。

于 2013-08-14T20:44:30.817 に答える
1

簡単なベンチマークを試して、大きなファイルの圧縮にかかる時間を計り、それが大きな違いを生むかどうかを確認することをお勧めします。GzipOutputStreamにはバッファリングがありますが、より小さなバッファです。最初は64Kバッファーを使用しますが、両方を実行する方が良い場合があります。

于 2009-07-04T14:49:33.283 に答える
0

javadocを読むと、BISが元のソースから読み取られたバイトをバッファリングするために使用されていることがわかります。生のバイトを取得したら、それらを圧縮して、BISをGISでラップします。GZIPからの出力をバッファリングすることは意味がありません。なぜなら、GZIPをバッファリングすることについて考える必要があるからです。誰がそれを行うのでしょうか?

new GzipInputStream( new BufferedInputStream ( new FileInputXXX
于 2009-07-04T23:10:54.823 に答える