我想编写从 ZIP 文件中提取文件的代码。
通常我会遍历文件,期待本地文件头或中央目录开始/结束签名。本地文件头的长度为
30
+ file name length
+ extra field length
字节,其中 file name length
和 extra field length
是存储在文件头位置 26 和 28 处的 16 位数字。文件数据将在标头之后开始,长度为 compressed size
字节,以 32 位数字形式存储在标头的位置 18 处。我希望在文件数据之后有下一个签名。
但是,有一些ZIP文件的
compressed size
为0。这些文件通常是作为流生成的,因此当生成本地文件头时,压缩后的大小还不知道。根据规范,此类文件由设置的本地文件头general purpose bit flag
的第3位指示。对于此类文件,压缩内容后跟一个数据描述符,其中包含文件的校验和和大小。下一个本地文件或中央目录只会跟随在该数据描述符之后。
我无法理解如何检测数据签名的位置,以便我知道从哪里开始寻找下一个签名。我真的很困惑为什么这似乎没有在任何地方得到解释,因为这似乎是一个非常明显的问题。
看起来压缩方法8(deflate)压缩后的数据是以块的形式存储的,并且有一个标记指示最后一个块,因此压缩方法本身提供了一种检测压缩数据结束的方法。然而,并非所有压缩方法都是如此。特别是,压缩方法0(无压缩)似乎没有提供这样的方式,因为未压缩的数据按原样存储。我也不能仅仅查找数据中的下一个签名,因为文件本身的未压缩数据可能包含签名。我也不能等待中央目录并在那里查找文件大小,因为我不知道如何找到中央目录的位置。
如何解析设置了位 3 且因此不包含压缩文件大小的文件?
“因为我不知道如何找到中央目录的位置。”
然后学习如何操作。您可以从 zip 文件的末尾搜索中央目录末尾的记录。这将为您提供中央目录的偏移量,或者如果该偏移量超过 232-2,则结束记录 32 位偏移量将包含 232-1,并且紧随其后的是 zip64 结束-of-central-directory-locator。这将具有 zip64 end-of-central-directory 记录的 64 位偏移量,该记录将具有中心目录的 64 位偏移量。
中央目录将包含所有长度。
不应该有一个 zip 文件为非自终止的压缩数据格式设置标志位 3,例如存储。您应该能够以流的形式读取 zip 文件,而不必从中央目录获取长度。