我应该使用GzipOutputStream和BufferedOutputStream的顺序

时间:2009-07-04 14:41:05

标签: java gzipoutputstream

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

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

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

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

6 个答案:

答案 0 :(得分:28)

  

我应该使用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,它对于对象稍微好一些,对文本来说更糟糕。我根本没有使用缓冲区大小。


对于对象流,我测试了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%

对于较小的文件(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%

答案 1 :(得分:26)

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

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

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

答案 2 :(得分:8)

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

我怀疑外面的BufferedOutputStream在没有显式缓冲的情况下会有很大帮助。为什么不?无论外部缓冲是否存在,GzipOutputStream都会以相同大小的块执行write()s到“...”。所以没有“......”可能的优化;你坚持使用GzipOutputStream write()s的大小。

另请注意,通过缓冲压缩数据而不是未压缩数据,您可以更有效地使用内存。如果你的数据经常达到6倍压缩,那么'inside'缓冲区相当于一个6X的“外部”缓冲区。

答案 3 :(得分:3)

通常你需要一个接近你的FileOutputStream的缓冲区(假设它代表什么),以避免过多的OS调用和频繁的磁盘访问。但是,如果你在GZIPOutputStream中写了很多小块,你也可以从GZIPOS周围的缓冲区中受益。原因是GZIPOS中的写入方法是同步的,并且还导致很少的其他同步调用和几个本机(JNI)调用(更新CRC32并进行实际压缩)。这些都会增加每个呼叫的额外开销。所以在这种情况下,我会说你会从两个缓冲区中受益。

答案 4 :(得分:2)

我建议您尝试一个简单的基准测试来计算压缩大文件所需的时间,看看它是否有很大的不同。 GzipOutputStream确实有缓冲但它是一个较小的缓冲区。我会用64K缓冲区做第一个,但你可能会发现两者都做得更好。

答案 5 :(得分:0)

读取javadoc,您将发现BIS用于缓冲从某些原始源读取的字节。获得原始字节后,您需要压缩它们,以便使用GIS包装BIS。缓冲GZIP的输出是没有意义的,因为需要考虑缓冲GZIP,谁会这样做呢?

new GzipInputStream( new BufferedInputStream ( new FileInputXXX