编辑:另一个建议...
从ZipFile
Apache Commons 实现来看,为您的项目有效地分叉似乎并不难。在您的字节数组周围创建一个包装器,RandomAccessFile
其中包含所需的所有 API 片段(我不认为有很多)。您已经表明您更喜欢界面ZipFile
,那么为什么不这样做呢?
我们对您的项目知之甚少,无法知道这是否会引发任何法律问题——即使您提供了详细信息,我怀疑这里的任何人都能够提供良好的法律建议——但我怀疑这不会超过一两个小时让这个解决方案启动并运行,我怀疑你会对它有合理的信心。
编辑:这可能是一个更有成效的答案......
如果您担心条目不连续,但又不想自己处理所有压缩方面,您可以考虑有效地重写数据的选项。创建一个新的ByteArrayOutputStream
,并在最后读取中央目录。ZipInputStream
对于中央目录中的每个条目,以您认为会满意的格式将条目(标题 + 数据)写入输出流。然后编写一个新的中央目录 - 如果您希望替换有效,您可能需要从头开始执行此操作,但如果您使用的代码您知道实际上不会读取中央目录,您可以只提供原始目录,忽略它可能无效的事实。只要它以正确的签名开始,那可能就足够了:)
完成后,将 theByteArrayOutputStream
转换为new byte[]
,将其包装在 a 中ByteArrayInputStream
,然后将其传递给ZipInputStream
or ZipArchiveInputStream
。
根据您的目的,您甚至可能不需要做那么多 - 您可以通过创建一个“迷你” 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 文件,所以我不知道我是否能够通过流处理它们
这意味着您要求的代码应该以您甚至无法预测的方式处理无效的 zip 文件。你能拒绝它有多无效?如果我给你 1000 个随机字节,根本不尝试将它们变成一个 zip 文件,你到底会用它做什么?
基本上,您需要更严格地确定问题,然后才能说出特定库是否是有效的解决方案。从各个地方收集一组 zip 文件是合理的,这些文件可能以众所周知的方式无效,并说“我必须能够支持所有这些”。稍后,如果事实证明这还不够好,您可能需要做一些工作。但是能够支持任何东西,无论多么损坏,都不是一个有效的要求。