Java 我应该使用GzipOutputStream和BufferedOutputStream的顺序是什么

Java 我应该使用GzipOutputStream和BufferedOutputStream的顺序是什么,java,gzipoutputstream,Java,Gzipoutputstream,有谁能推荐我是否应该做以下事情: os = new GzipOutputStream(new BufferedOutputStream(...)); 或 哪个更有效?我应该使用BufferedOutputStream吗?我建议您尝试一个简单的基准测试,以确定压缩一个大文件所需的时间,并查看它是否有很大的不同。GzipOutputStream确实有缓冲区,但它是一个较小的缓冲区。第一种方法是使用64K缓冲区,但您可能会发现两者都做得更好。当数据的最终目的地最好是以比代码更大的块进行读/写时,缓冲

有谁能推荐我是否应该做以下事情:

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


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

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

当数据的最终目的地最好是以比代码更大的块进行读/写时,缓冲会有所帮助。因此,您通常希望缓冲区尽可能靠近需要较大块的位置。在您的示例中,这是省略的“…”,因此请使用GzipOutputStream包装BufferedOutputStream。并且,调整BufferedOutputStream缓冲区大小,以匹配测试显示最适合目标的内容

我怀疑外部的BufferedOutputStream在没有显式缓冲的情况下会有多大帮助。为什么不呢?无论外部缓冲是否存在,GzipOutputStream都将在相同大小的块中对“…”执行write()操作。所以不可能对“…”进行优化;您必须知道GzipOutputStream write()的大小


还要注意的是,通过缓冲压缩的数据而不是未压缩的数据,可以更有效地使用内存。如果您的数据经常进行6X压缩,“内部”缓冲区相当于“外部”缓冲区6X的大小。

阅读javadoc,您会发现BIS用于缓冲从某个原始源读取的字节。一旦你得到了原始字节,你就要压缩它们,这样你就可以用GIS包装BIS了。缓冲来自GZIP的输出是没有意义的,因为需要考虑缓冲GZIP是什么,谁来做呢

new GzipInputStream( new BufferedInputStream ( new FileInputXXX
我应该使用
GzipOutputStream
BufferedOutputStream

对于对象流,我发现在输入和输出的gzip流周围包装缓冲流几乎总是明显更快。对象越小,效果越好。在所有情况下都比没有缓冲流更好或相同

ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis)));
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));
reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis)));
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos)));
然而,对于文本和直接字节流,我发现这是一个折腾——缓冲流周围的gzip流只是稍微好一点。但在所有情况下都比没有缓冲流要好

ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis)));
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));
reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis)));
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos)));
每个版本我都运行了20次,第一次停止运行,其余的取平均值。我还尝试了buffered gzip buffered,它对对象稍微好一点,对文本更差。我根本不玩缓冲区大小的游戏


对于对象流,我测试了2个10兆字节的序列化对象文件。对于较大的文件(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秒)


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

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

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


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

“您想压缩它们,以便用GIS包装BIS”-GIS不会压缩。它会解压。FWIW我正在努力理解你在回答的后半部分中的一般观点。这只对了一半:GZIPOutputStream内部输出缓冲区决定了一次可以压缩多少字节,但是如果你给它提供小块字节(或单个字节),即使输出缓冲区可以容纳更多的数据,只要平减器能够发出一个压缩数据块,它仍然会写入备份输出流。但如果您在GZIPOutputStream前面放置第二个缓冲区,确保只写入大的数据块,这就没问题了。所以答案仍然是正确的,只是细节比这要复杂一点。最好能看到准确的输入数据和标准偏差,否则结果是不可复制的