【问题标题】:Read & Write Uncompressed Zip Data from an InputStream Java [closed]从 InputStream Java 中读取和写入未压缩的 Zip 数据 [关闭]
【发布时间】:2021-11-28 00:38:55
【问题描述】:

目前,我正在从网站下载一个 jar 文件,这些类被进一步处理,但资源没有。这意味着我在从 URL 读取时不需要解压缩,在写入文件时不需要重新压缩资源。

但是,给定一个 ZipInputStream,我知道没有任何方法可以读取 zip 条目压缩的数据并将其直接写入带有 NIO 的文件。通常使用 NIO 带文件,我可以使用 Files#copy 功能来执行此操作,但我是从网络下载这些文件,因此我没有这种奢侈。

基本上,我有一个 ZipInputStream 和一个用于 Zip 文件的 NIO 文件系统,如何在不解压缩和重新压缩每个条目的情况下将此输入流中的一些(不是全部)数据复制到文件中?

【问题讨论】:

  • 发布一个最小的可重现代码示例。听起来您正在尝试在观察问题所在和问题之前添加性能更改。
  • 我已经分析了我的代码,所以我知道这是一个问题。它需要大约 20% 的运行时间。没有最低限度的可重现代码示例,因为我一开始就不知道如何做到这一点。
  • 尝试拆分任务:将 url 下载到文件然后处理它。您可以隔离一些显示或促成您观察到的问题的代码部分,以添加回此问题。

标签: java zip nio


【解决方案1】:

不清楚你在这里问什么。

压缩到压缩

您的意思是:您想通过网络流式传输一个 zip 文件,将其保存到磁盘上的本地计算机,但只保存其中的一些文件。您想在不实际进行任何(解)压缩的情况下执行此操作。例如,如果流包含一个包含 18 个文件的 zip,您希望保存名称不以 .class 结尾的 8 个文件,但以将压缩字节直接从网络流式传输到 压缩的文件,无需任何解压缩或重新压缩。

从这个意义上说,它相当于将 zip 文件从网络保存到磁盘,然后尝试有效地清除一些条目。除了一口气。

这是一个坏主意。这里没有简单的答案。这在技术上是可行的,但有很多警告,我敢肯定你不会想要这个。

如果您需要更多关于为什么会这样的上下文,请向下滚动到此答案的末尾。

压缩到文件

如果您的意思是:“我想从网络传输一个 zip,跳过其中一些而不解压缩跳过的项目或将它们完全保存到磁盘(压缩或不压缩),并编写我想要保持直截了当的那些从网络到磁盘,即时解压缩”——这很简单。

使用.getNextEntry() 跳过。将ZipInputStream 视为单个入口流。它会 EOF 直到您移动到下一个条目,这使得它“工作”。

这是一个示例,它从 zip 文件中读取所有条目,跳过以 .class 结尾的所有条目,并将所有其他条目写入磁盘,即时解压缩:

public void unpackResources(Path zip, Path tgt) throws IOException {
  try (InputStream raw = Files.newInputStream(zip)) {
    ZipInputStream zip = new ZipInputStream(raw);
    for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
      if (entry.getName().endsWith(".class")) continue;
      Path to = tgt.resolve(entry.getName());
      try (OutputStream out = Files.newOutputStream(to)) {
        zip.transferTo(to);
      }
    }
  }
}

in.transferTo(out) 是等效于Files.copy 的输入/输出流。 If 从 in 中读取字节并将它们直接扔到 out 中,直到 in 表示没有更多字节可提供。


上下文:为什么 zip-to-stripped-zip 不可行?

如果您完全单独处理批处理中的每个文件,压缩有时效率极低:毕竟,您无法利用文件之间的重复模式。想象一下压缩一个常见婴儿名字的数据库,其中输入数据由每个名字的 1 个文件组成,它们只包含文本 Name: Joanna,一遍又一遍。您确实需要利用那些重复的 Name: 条目来获得良好的压缩率。

如果压缩格式正确,那么您想要的就行不通了:您只有一个表(我在这里过度简化了压缩的工作原理)将较短的序列映射到较长的序列,但它是经过设计的用于有效存储整个交易。如果你去掉一半的文件,那张表可能就不再有效了。如果您不复制表格,则压缩字节没有任何意义。

一些压缩格式做错了,完全独立处理每个文件,在“名称文件”测试中得分相当低。不幸的是,ZIP 就是这样一种格式。这确实意味着从技术上讲,将压缩数据直接流式传输到文件中/剥离一些文件可以在不解压缩/重新压缩的情况下完成,假设一个使用所有常用算法的 zip 文件(ZIP 与其说是一种算法,它是一个容器格式。然而,99% 的 zip 使用特定的算法,许多 zip 阅读器在其他 zip 上失败)。加密可能也会在这里引起问题。

考虑到这有点奇怪,通常压缩库不提供此功能;除非是针对常见的 zip 文件,否则无法做到这一点。

你必须自己写。我不确定这是否值得。解压缩和重新压缩非常快(zip 在 30 年前是可行的。在这个数字上撒上一些摩尔定律,你可能会感觉到这些天它是多么微不足道。你的磁盘将是瓶颈,而不是 CPU。即使速度很快SSD)。

【讨论】:

  • 我的输入保证是未加密的,并且我已经使用分析器验证了解压缩/重新压缩是一个问题(大约 20% 的运行时间)。我正在考虑使用外部库,我发现了一些可以让我访问压缩数据的库,但是,将它与 NIO 和我的其他代码集成是困难的部分。
  • 您是在尝试执行 zip-to-zip 部分还是 zip-to-files 部分?对于 NIO,您是指“非阻塞 I/O”还是java.nio.files
  • java.nio.files 主要是,我正在做 zip-to-zip
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-30
  • 2015-06-16
  • 1970-01-01
  • 2023-04-09
  • 2012-01-23
  • 1970-01-01
  • 2014-03-20
相关资源
最近更新 更多