【问题标题】:ZipEntry.STORED for files that are already compressed?ZipEntry.STORED 用于已经压缩的文件?
【发布时间】:2016-02-01 22:24:54
【问题描述】:

我正在使用ZipOutputStream 压缩一堆文件,这些文件混合了已压缩的格式以及许多大型高度可压缩格式(如纯文本)。

大多数已经压缩的格式都是大文件,花费 cpu 和内存重新压缩它们是没有意义的,因为它们永远不会变小,有时会在极少数情况下稍微变大。

我在检测到预压缩文件时尝试使用.setMethod(ZipEntry.STORED),但它抱怨我需要为这些文件提供size, compressedSize and crc

我可以使用以下方法使其工作,但这需要我阅读文件两次。一次计算CRC32,然后再次将文件实际复制到ZipOutputStream

// code that determines the value of method omitted for brevity
if (STORED == method)
{
    fze.setMethod(STORED);
    fze.setCompressedSize(fe.attributes.size());
    final HashingInputStream his = new HashingInputStream(Hashing.crc32(), fis);
    ByteStreams.copy(his,ByteStreams.nullOutputStream());
    fze.setCrc(his.hash().padToLong());
}
else
{
    fze.setMethod(DEFLATED);
}
zos.putNextEntry(fze);
ByteStreams.copy(new FileInputStream(fe.path.toFile()), zos);
zos.closeEntry();

有没有一种方法可以提供这些信息而无需两次读取输入流?

【问题讨论】:

    标签: java zipoutputstream


    【解决方案1】:

    简答:

    鉴于我必须解决这个问题,我无法确定只读取一次文件并使用标准库计算 CRC 的方法。

    我确实找到了一个优化,平均减少了大约 50% 的时间。

    我预先计算了要同时存储的文件的CRC 与限制为Runtime.getRuntime().availableProcessors()ExecutorCompletionService 并等待它们完成。其有效性因需要计算 CRC 的文件数量而异。文件越多,收益越大。

    然后在.postVisitDirectories() 中,我将PipedOutputStream 从在临时Thread 上运行的PipedInputStream/PipedOutputStream 对中包裹ZipOutputStream,以将ZipOutputStream 转换为InputStream 我可以传递到@ 987654334@ 将ZipOutputStream 的结果上传到远程服务器,同时串行写入所有预先计算的ZipEntry/Path 对象。

    现在这已经足够好了,可以处理即时需求的300+GB,但是当我得到10TB 的工作时,我会考虑解决它并尝试在不增加太多复杂性的情况下找到更多优势。

    如果我在时间上想出更好的东西,我会用新的实现来更新这个答案。

    长答案:

    我最终编写了一个洁净室 ZipOutputStream,它支持多部分 zip 文件、智能压缩级别与 STORE 相比,并且能够在我读取并在流末尾写出元数据时计算 CRC .


    为什么 ZipOutputStream.setLevel() 交换不起作用:

    ZipOutputStream.setLevel(NO_COMPRESSION/DEFAULT_COMPRESSION) hack 不是一种可行的方法。我对数百个进行了广泛的测试 大量数据、数千个文件夹和文件以及测量结果 确凿。它对计算 CRC 没有任何好处 STORED 文件与在NO_COMPRESSION 压缩它们。它实际上是 较慢大幅提升!

    在我的测试中,文件位于网络安装驱动器上,因此请阅读 文件已通过网络将文件两次压缩到 计算CRC 然后再次添加到ZipOutputStream 为 比将所有文件处理一次为DEFLATED 更快或更快 并更改ZipOutputStream 上的.setLevel()

    网络访问没有进行本地文件系统缓存。 这是一个更糟糕的情况,处理本地磁盘上的文件会 由于本地文件系统缓存,速度要快得多。

    因此,这种 hack 是一种幼稚的方法,并且基于错误的假设。它正在处理 即使在NO_COMPRESSION级别也通过压缩算法的数据 而且开销比两次读取文件要高。

    【讨论】:

      猜你喜欢
      • 2020-05-03
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 2021-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      相关资源
      最近更新 更多