【发布时间】:2009-07-04 14:41:05
【问题描述】:
谁能推荐我是否应该这样做:
os = new GzipOutputStream(new BufferedOutputStream(...));
或
os = new BufferedOutputStream(new GzipOutputStream(...));
哪个更有效率?我应该使用 BufferedOutputStream 吗?
【问题讨论】:
标签: java gzipoutputstream
谁能推荐我是否应该这样做:
os = new GzipOutputStream(new BufferedOutputStream(...));
或
os = new BufferedOutputStream(new GzipOutputStream(...));
哪个更有效率?我应该使用 BufferedOutputStream 吗?
【问题讨论】:
标签: java gzipoutputstream
GZIPOutputStream 已经带有内置缓冲区。因此,没有必要在链中将 BufferedOutputStream 放在它旁边。 gojomo 的出色回答已经为放置缓冲区的位置提供了一些指导。
GZIPOutputStream 的默认缓冲区大小仅为 512 字节,因此您需要通过构造函数参数将其增加到 8K 甚至 64K。 BufferedOutputStream 的默认缓冲区大小为 8K,这就是为什么在组合默认 GZIPOutputStream 和 BufferedOutputStream 时可以衡量优势的原因。这一优势也可以通过适当调整 GZIPOutputStream 的内置缓冲区大小来实现。
所以,回答你的问题:“我应该使用 BufferedOutputStream 吗?” → 不,在你的情况下,你不应该使用它,而是将 GZIPOutputStream 的缓冲区设置为至少 8K。
【讨论】:
当数据的最终目的地最好以更大的块读取/写入时,缓冲会有所帮助,而不是您的代码会以其他方式推送它。因此,您通常希望缓冲尽可能接近想要更大块的位置。在您的示例中,这是省略的“...”,因此将 BufferedOutputStream 与 GzipOutputStream 包装起来。并且,调整 BufferedOutputStream 缓冲区大小以匹配测试显示最适合目标的内容。
我怀疑外部的 BufferedOutputStream 在没有显式缓冲的情况下会有所帮助(如果有的话)。为什么不?无论外部缓冲是否存在,GzipOutputStream 都会以相同大小的块对“...”执行其 write()。所以不可能对“...”进行优化;您被 GzipOutputStream write() 的大小所困扰。
另请注意,通过缓冲压缩数据而不是未压缩数据,您可以更有效地使用内存。如果您的数据经常实现 6 倍压缩,则“内部”缓冲区相当于 6 倍大的“外部”缓冲区。
【讨论】:
通常,您希望在 FileOutputStream 附近有一个缓冲区(假设这就是 ... 所代表的内容),以避免过多调用操作系统和频繁访问磁盘。但是,如果您正在向 GZIPOutputStream 写入大量小块,您也可能会从 GZIPOS 周围的缓冲区中受益。原因是 GZIPOS 中的 write 方法是同步的,并且还导致很少的其他同步调用和几个本机 (JNI) 调用(更新 CRC32 并进行实际压缩)。这些都增加了每次调用的额外开销。所以在这种情况下,我会说你将从这两个缓冲区中受益。
【讨论】:
GzipOutputStream和BufferedOutputStream应该使用什么顺序
对于对象流,我发现将缓冲流包裹在 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%
【讨论】:
我建议你尝试一个简单的基准来计算压缩一个大文件需要多长时间,看看它是否有很大的不同。 GzipOutputStream 确实有缓冲,但它是一个较小的缓冲区。我会用 64K 缓冲区做第一个,但你可能会发现两者都做更好。
【讨论】:
阅读 javadoc,您会发现 BIS 用于缓冲从某些原始源读取的字节。一旦你得到你想要压缩的原始字节,你就可以用 GIS 包装 BIS。缓冲 GZIP 的输出是没有意义的,因为需要考虑缓冲 GZIP 会怎样,谁来做呢?
new GzipInputStream( new BufferedInputStream ( new FileInputXXX
【讨论】: