【问题标题】:Preferred way to use Java ZipOutputStream and BufferedOutputStream使用 Java ZipOutputStream 和 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 有一个内部缓冲区,因此它不会将单个字节写入底层流。根据底层流类型(例如,文件与套接字)和缓冲区的相对大小,您可能会或可能不会看到任何差异。

标签: java io outputstream


【解决方案1】:

您应该始终将BufferedOutputStreamZipOutputStream 包裹起来,而不是相反。见以下代码:

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 中所述:

不属于BufferedOutputStreamZipOutputStream 的方法也将不可用。例如。 putNextEntrycloseEntry

【讨论】:

  • 我确信我的回答是正确的。但请随意尝试两种方式并比较性能(或调试它们)。
  • 我的意思是,比较两者之间的任何性能是没有意义的。将ZipOutputStream 包装在BufferedOutputStream 中完全没有意义,因为它不会公开putNextEntrycloseEntry 方法。
  • 拒绝投票作为答案并没有提到如果包装错误,ZipOutputStream 的方法在流上时不可用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 1970-01-01
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-01-25
相关资源
最近更新 更多