如何测试一个文件是否为zip文件?有什么好的方法?

18

我正在寻找一种新的文件格式规范,规范说明文件可以是基于xml的,也可以是一个包含xml文件和其他文件的zip文件。

两种情况下的文件扩展名相同。有哪些方法可以测试文件以决定是否需要解压缩还是直接读取?

9个回答

31

ZIP文件格式是由PKWARE定义的。你可以在这里找到他们的文件规范。

在文档的最上面,你将会找到头部规范:

A. 本地文件头:

    local file header signature     4 bytes  (0x04034b50)
    version needed to extract       2 bytes
    general purpose bit flag        2 bytes
    compression method              2 bytes
    last mod file time              2 bytes
    last mod file date              2 bytes
    crc-32                          4 bytes
    compressed size                 4 bytes
    uncompressed size               4 bytes
    file name length                2 bytes
    extra field length              2 bytes

    file name (variable size)
    extra field (variable size)
根据这段内容,可以看出文件头的前4个字节应该是文件签名,其十六进制值应为0x04034b50。文件中的字节顺序相反 - PKWARE指定“所有值都存储在小端字节顺序中,除非另有说明。”因此,如果您使用十六进制编辑器查看文件,则会看到50 4b 03 04作为前4个字节。 您可以使用这个方法来检查文件是否为zip文件。如果您在记事本中打开文件,您会注意到前两个字节(50和4b)是ASCII字符PK。

4
ZIP文件格式在不同的供应商之间并没有变化。它最初由PKWARE定义,但现在许多其他供应商都支持相同的压缩格式。该格式在头部指定了PK,因此即使是其他供应商也将包括头部的这一部分。不同的文件格式(如arc、7z、lhz、gzip等)将具有不同的规范和不同的头部,但ZIP文件始终会在头部中包含这个信息。 - Simon P Stevens
6
如果你的系统是小端字节序,那么文件中的字节顺序将相反。 - Steve Jessop
1
@Steve:是的,我澄清了。PKWARE在格式中指定小端序。 - Simon P Stevens
从技术上讲,根据Cheeso的评论,这个答案是不正确的。为了符合规范,您必须扫描文件以查找中央目录结束(EoCD)标记。规范绝不会阻止存档软件在本地文件头之前或之后插入任意数据。像您建议的那样扫描本地文件头的文件容易出错,除非尝试从损坏的存档中恢复数据。这进一步复杂化了EoCD头部末尾存在可变长度注释的情况。老实说,ZIP是一个设计不良且过时的格式。 - Dan Bechard
有关这个令人烦恼的难题的更多信息,请参见https://github.com/thejoshwolfe/yauzl/issues/48#issuecomment-266587526。 - Dan Bechard
显示剩余9条评论

12

是的,但是让提问者知道... '有效的魔数'并不能保证文件不损坏或类型错误。 - KMån
2
确实。但是,如果他们的问题只是区分两个有效格式,那么魔数就是最好的选择。 - Amber
1
一个zip文件没有固定的魔数。通常,zip文件以这些序列开头,但并不是每个zip文件都是这样。 - Cheeso

1

虽然不是一个好的解决方案,但只是随便想一下...怎么样:

try
{
LoadXmlFile(theFile);//Exception if not an xml file
}
catch(Exception ex)
{
LoadZipFile(theFile)
}

我投了赞成票,但个人不喜欢使用try catch来控制程序。我正在寻找更精确的测试方法。不过还是感谢你的建议。 - Phil Hannent
我同意 - 一般的程序流程中不应该使用try/catch(它会使程序变慢几个数量级,而且从哲学上讲,就像是在黑板上刮指甲)。 - Contango

1

检查文件的前几个字节,查看魔数。Zip文件以PK(50 4B)开头。由于XML文件不能以这些字符开头并仍然有效,因此您可以相当确定文件类型。


2
压缩文件没有魔数。如果维基百科说或暗示有,那是错误的。 - Cheeso
3
@Cheeso 是的,有的。请阅读格式 http://www.pkware.com/documents/casestudies/APPNOTE.TXT 并注意“本地文件头标记”及其定义值。 - Yacoby
2
我理解你从文本中读出的想法,但那是不正确的。虽然文本有些模糊,但实际上并没有所谓的魔数。http://en.wikipedia.org/wiki/ZIP_(file_format)以及实践经验表明,你在假设一个魔数时对规范的解释是错误的。请查看WinZip或Infozip生成的自解压缩归档文件。它既是PE-COFF文件又是zip文件。它使用MZ魔数,但可以被兼容的ZIP工具读取为zip文件。 - Cheeso

1

3
是的,有一个神奇数字:zip文件以PK(50 4B 03 04)开头。 - RvdK

1
你可以使用file来查看它是文本文件(xml)还是可执行文件(zip)。 向下滚动以查看示例。

哎呀,我以为会有一个叫做file()的系统调用文件。 - ccheneson

1

您可以检查文件是否包含有效的XML头。如果没有,请尝试解压缩它。

请参阅此处获取XML规范。


0

您可以尝试解压缩它——XML 文件极不可能是有效的 zip 文件,或者可以像其他人所说的那样检查魔数。


0

这取决于你使用的是什么,但 zip 库可能有一个函数来测试文件是否为 zip 文件,像 is_zip、test_file_zip 或其他类似的函数。

或者通过使用上面给出的魔数创建自己的函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接