我应该使用GzipOutputStream和BufferedOutputStream的顺序

san*_*ity 28 java gzipoutputstream

任何人都可以推荐我是否应该这样做:

os = new GzipOutputStream(new BufferedOutputStream(...));
Run Code Online (Sandbox Code Playgroud)

要么

os = new BufferedOutputStream(new GzipOutputStream(...));
Run Code Online (Sandbox Code Playgroud)

哪个更有效率?我应该使用BufferedOutputStream吗?

Gra*_*ray 28

我应该使用什么顺序GzipOutputStreamBufferedOutputStream

对于对象流,我发现将gzip流周围的缓冲流包装为输入和输出几乎总是明显更快.物体越小,这就越好.在所有情况下都更好或相同,然后没有缓冲流.

ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis)));
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));
Run Code Online (Sandbox Code Playgroud)

然而,对于文本和直字节流,我发现它是一个折腾 - 缓冲流周围的gzip流只是略微好一点.但在所有情况下都更好,然后没有缓冲流.

reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis)));
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos)));
Run Code Online (Sandbox Code Playgroud)

我运行了每个版本20次并切断了第一次运行并平均其余部分.我也尝试过buffered-gzip-buffered,它对于对象稍好一些,对文本来说更糟糕.我根本没玩缓冲区大小.


对于对象流,我测试了10兆字节的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%
Run Code Online (Sandbox Code Playgroud)

对于较小的文件(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%
Run Code Online (Sandbox Code Playgroud)

对于文本读写器,我使用了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%
Run Code Online (Sandbox Code Playgroud)


bar*_*uin 27

GZIPOutputStream已经内置了一个缓冲区.因此,没有必要在链中放置一个BufferedOutputStream.gojomo的优秀答案已经提供了缓冲区放置的一些指导.

GZIPOutputStream的默认缓冲区大小仅为512字节,因此您需要通过构造函数参数将其增加到8K甚至64K.BufferedOutputStream的默认缓冲区大小为8K,这就是为什么在组合默认GZIPOutputStream和BufferedOutputStream时可以测量优势的原因.通过适当调整GZIPOutputStream的内置缓冲区大小,也可以实现这一优势.

所以,回答你的问题:"我应该使用BufferedOutputStream吗?" →不,在您的情况下,您不应该使用它,而是将GZIPOutputStream的缓冲区设置为至少8K.

  • 这只是对了一半:GZIPOutputStream 内部输出缓冲区决定了一次可以压缩多少字节,但是如果你向它提供小块字节(或单个字节),它仍然会在 Deflater 后立即写入支持输出流可以发出压缩数据块,即使输出缓冲区可以容纳更多数据。但是,如果您在 GZIPOutputStream 前面放置第二个缓冲区,确保只写入大块,那就没问题了。所以答案还是正确的,只是细节比那复杂一点。 (4认同)

goj*_*omo 8

当数据的最终目的地以更大的块读取/写入时,缓冲有助于比您的代码推送它更大的块.所以你通常希望缓冲尽可能接近那些想要更大块的地方.在您的示例中,这是省略的"...",因此使用GzipOutputStream包装BufferedOutputStream.并且,调整BufferedOutputStream缓冲区大小以匹配测试显示最适合目标的测试.

我怀疑外面的BufferedOutputStream会有多大帮助,如果有的话,没有明确的缓冲.为什么不?无论外部缓冲是否存在,GzipOutputStream都会以相同大小的块执行write()s到"...".所以没有"......"可能的优化; 你坚持使用GzipOutputStream write()s的大小.

另请注意,通过缓冲压缩数据而不是未压缩数据,您可以更有效地使用内存.如果你的数据经常实现6X压缩,那么'inside'缓冲区相当于6X的"外部"缓冲区.


roo*_*beh 5

通常,您需要一个靠近 FileOutputStream 的缓冲区(假设这就是 ... 代表的内容),以避免对操作系统进行过多调用和频繁的磁盘访问。但是,如果您要向 GZIPOutputStream 写入大量小块,您也可能会受益于 GZIPOS 周围的缓冲区。原因是 GZIPOS 中的 write 方法是同步的,并且还导致很少的其他同步调用和几个本机 (JNI) 调用(以更新 CRC32 并进行实际压缩)。这些都会增加每次调用的额外开销。因此,在这种情况下,我想说您将从这两个缓冲区中受益。