用Java解压缩内存中的ZIP文件
我正在下载包含XML的压缩文件,由于延迟要求,我希望避免在操作之前将zip文件写入磁盘。但是,java.util.zip
这不足以满足我的需求。没有办法说“这是一个zip文件的字节数组,请使用它”而不将其转换为流,并且ZipInputStream
它不可靠,因为它会扫描条目标头(请参阅EDIT下面的讨论,以了解为什么它不可靠)。
我尚无法访问要处理的zip文件,因此我不知道我是否能够通过来处理它们ZipInputStream
,因此我需要找到一种适用于任何有效ZIP文件的解决方案,因为一旦投入生产,失败的代价就会很高。
假设ZipInputStream不起作用,在没有条目头的情况下我该怎么办才能解决此问题?我正在使用Wikipedia的定义作为标准,其中包括有关如何正确解压缩zip文件(在下面引用)的注释。
Apache Commons
Zip库很好地记录了使用Stream的一些问题(包括解决方案和Java的问题)。根据维基百科和个人经验,我将进一步添加,并且可能不会填写条目标题上的size和crc字段(我在这些字段中带有-1的文件)。感谢centic提供此链接。
另外,让我引用有关该主题的维基百科:
正确读取zip存档的工具必须扫描zip中央目录等各个字段的签名。他们不能扫描条目,因为只有目录指定了文件块的起始位置。扫描可能会导致误报,因为这种格式不会禁止其他数据出现在块之间,也不会禁止包含此类签名的未压缩流。
请注意,它ZipInputStream
扫描的是条目而不是中央目录,这是它的问题。
如果有人感兴趣,则可以使用此脚本来生成有效的ZIP文件,而该文件无法ZipInputStream
从现有的ZIP文件中读取。因此,作为对该封闭问题的最终编辑,我需要一个可以读取诸如此脚本生成的文件之类的文件的库。
回答:
编辑:另一个建议…
看着ZipFile
从Apache下议院实现,它看起来不会 太
硬有效餐桌,对您的项目。在您的字节数组周围创建一个包装器,该包装器具有所有RandomAccessFile
必需的API部分(我认为不是很多)。您已经表明,您更喜欢该界面ZipFile
,那么为什么不这样做呢?
我们对您的项目了解得还不够多,所以不知道这是否会引起任何法律问题-即使您提供了详细信息,我也怀疑这里的任何人都能够提供良好的法律建议-
但我怀疑这样做不会花费太多时间一个或两个小时的时间来启动该解决方案并开始工作,我怀疑您对此有足够的信心。
编辑:这可能是一个更有成效的答案…
如果您担心条目不连续,但又不想自己处理所有压缩方面,则可以考虑选择一种有效 重写 数据的方法。创建一个new
ByteArrayOutputStream
,并在最后阅读中央目录。对于中央目录中的每个条目,以您认为ZipInputStream
会满意的格式将条目(标头+数据)写到输出流中。然后编写一个新的中央目录-
如果您希望您的替换有效,则可能需要从头开始,但是如果您使用的代码 知道 实际上不会读取中央目录,则只需提供原始目录即可。
,而忽略了它随后可能无效的事实。只要它以正确的签名开头,就足够了:)
完成此操作后,请将转换ByteArrayOutputStream
为 新的
byte[]
,将其包装在中ByteArrayInputStream
,然后将其传递给ZipInputStream
或ZipArchiveInputStream
。
根据您的目的,您甚至不需要做那么多-您可以通过创建一个“ mini” zip文件(每次只从目录中读取一个条目)来提取每个文件。 。
这 确实需要 了解zip文件格式,但不能完全有效-仅了解骨架。这不是像完全使用现有的API那样的快速简便的修复方法,但是它不会花 很
长时间。它不能保证它将能够读取所有无效文件(怎么办?),但是可以保护您免受您似乎特别关注的“条目之间的数据”问题。希望这至少是一个有用的主意…
没有办法说“这是一个zip文件的字节数组,请使用它”
就在这里:
byte[] data = ...;ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
ZipInputStream zipStream = new ZipInputStream(byteStream);
剩下的问题就是是否ZipInputStream
可以处理您要提供的所有zip文件-但我不会这么快地将其注销。
当然,还有其他可用的API。例如,您可能需要查看Apache Commons
Compress。即使ZipFile
需要一个文件,ZipArchiveInputStream
也不需要-
再次如此,您可以使用ByteArrayInputStream
。编辑:ZipArchiveStream
似乎也不
从中央目录中读取。我希望它可以用于markSupported
事前检查,但似乎没有…
编辑:在对问题的评论中,我问你在哪里读到zip文件不必包含条目数据。您引用了维基百科:
“正确读取zip存档的工具必须扫描zip中央目录各个字段的签名。它们不能扫描条目,因为只有目录指定了文件块的起始位置。由于格式不正确,扫描可能导致误报。禁止其他数据位于数据块之间或包含此类签名的未压缩流之间。”
这与输入数据是可选的不同。就是说在尴尬的地方可能会有 多余的 数据,而不是条目可能会完全丢失。基本上是说条目不应该假定是 连续的
。我可以很高兴地承认,ZipInputStream
可能不是在文件末尾读取中央目录,而是找到能做到这一点的代码与找到能应对不存在的条目数据的代码不同。
然后,您写:
我可能会进一步补充说,该邮政编码是否有效不是我关心的问题。使用它是。
…这表示您想要的代码将处理无效的zip文件。与此结合:
我还没有访问要处理的zip文件的权限,所以我不知道我是否能够通过流处理它们。
这意味着您要查询的代码应能处理甚至无法预测的无效zip文件。拒绝它对您来说将有多无效?如果我给您1000个随机字节,而根本不尝试将它们作为zip文件,那么您将如何处理呢?
基本上,您甚至需要说出某个特定库是否是有效的解决方案之前,就必须更紧密地解决问题。从各个地方收集一组zip文件是合理的,这在众所周知的方式中可能是无效的,并说“我必须能够支持所有这些文件”。后来,如果结果证明还不够好,您
可能 需要做一些工作。但是,要能够支持任何东西,无论它多么残破,根本不是一个有效的要求。
以上是 用Java解压缩内存中的ZIP文件 的全部内容, 来源链接: utcz.com/qa/428881.html