使用 Java ZipOutputStream 和 BufferedOutputStream 的首选方式
Posted
技术标签:
【中文标题】使用 Java ZipOutputStream 和 BufferedOutputStream 的首选方式【英文标题】:Preferred way to use Java ZipOutputStream and BufferedOutputStream 【发布时间】:2013-01-05 21:48:20 【问题描述】:在 Java 中,我先实例化 ZipOutputStream 还是先实例化 BufferedOutputStream 是否重要?示例:
FileOutputStream dest = new FileOutputStream(file);
ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(dest));
// use zip output stream to write to
或者:
FileOutputStream dest = new FileOutputStream(file);
BufferedOutputStream out = new BufferedOutputStream(new ZipOutputStream(dest));
// use buffered stream to write to
在我的非科学时间安排中,我似乎无法在这里说出太多不同。我在 Java API 中看不到任何说明这些方法之一是否必要或首选的内容。有什么建议吗?似乎先压缩输出然后缓冲写入会更有效。
【问题讨论】:
理论上,压缩然后缓冲会更快。但是,GZipOutputStream
有一个内部缓冲区,因此它不会将单个字节写入底层流。根据底层流类型(例如,文件与套接字)和缓冲区的相对大小,您可能会或可能不会看到任何差异。
【参考方案1】:
您应该始终将BufferedOutputStream
与ZipOutputStream
包裹起来,而不是相反。见以下代码:
FileOutputStream fos = new FileOutputStream("hello-world.zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);
try
for (int i = 0; i < 10; i++)
// not available on BufferedOutputStream
zos.putNextEntry(new ZipEntry("hello-world." + i + ".txt"));
zos.write("Hello World!".getBytes());
// not available on BufferedOutputStream
zos.closeEntry();
finally
zos.close();
正如 cmets 所说,putNextEntry()
和 closeEntry()
方法在 BufferedOutputStream
上不可用。不调用这些方法ZipOutputStream
会引发异常java.util.zip.ZipException: no current ZIP entry
。
为了完整起见,值得注意的是,finally 子句仅在ZipOutputStream
上调用close()
。这是因为按照惯例,所有内置的 Java 输出流包装器实现都会传播关闭。
编辑
我只是反过来测试了它。事实证明,用BufferedOutputStream
包装ZipOutputStream
,然后只在其上调用write()
(不创建/关闭条目)不会抛出ZipException
。相反,生成的 ZIP 文件将损坏,其中没有任何条目。
【讨论】:
这样的话,缓冲有什么意义吗?我不是在这里争论,只是好奇到目前为止是否有人检查过。 正如您在MrSmith42's 答案的第一部分中看到的那样,通过在写入磁盘之前缓冲已经压缩的输出流,使用内部 BufferedOutputStream 可能是有益的。您将使用更多内存(用于在刷新到磁盘之前将 zip 压缩字节保存在内存缓冲区中)但效率更高,因为磁盘 I/O 是在更大的字节块中完成的(BufferedOutputStream 的缓冲区大小已初始化与)。ZipOutputStream
中的 buffer size BufferedOutputStream 对您来说性能最高,您应该自己 figure out,【参考方案2】:
你应该:
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
因为您想缓冲写入磁盘的内容(因为这在大数据块中比在许多小数据块中效率更高)。
这个
new BufferedOutputStream(new ZipOutputStream(dest));
会在 zip 压缩之前缓冲。但这一切都发生在内存中,不需要缓冲,因为很多小内存访问的速度与少数大内存访问的速度大致相同。 在内存中,所需时间通常与读取/写入的字节数成正比。
如 cmets 中所述:
不属于BufferedOutputStream
的ZipOutputStream
的方法也将不可用。例如。 putNextEntry
和 closeEntry
。
【讨论】:
我确信我的回答是正确的。但请随意尝试两种方式并比较性能(或调试它们)。 我的意思是,比较两者之间的任何性能是没有意义的。将ZipOutputStream
包装在BufferedOutputStream
中完全没有意义,因为它不会公开putNextEntry
和closeEntry
方法。
拒绝投票作为答案并没有提到如果包装错误,ZipOutputStream 的方法在流上时不可用。以上是关于使用 Java ZipOutputStream 和 BufferedOutputStream 的首选方式的主要内容,如果未能解决你的问题,请参考以下文章
ZipOutputStream 类的 closeEntry()
Java ??????ZipOutputStream ??????????????????
使用 ZipOutputStream 和 FileStream 压缩文件时出现异常