【问题标题】:How to check type of files using the header file signature (magic numbers)?如何使用头文件签名(幻数)检查文件类型?
【发布时间】:2021-12-02 06:50:44
【问题描述】:

通过输入带有扩展名的文件,我的代码成功地从“幻数”中检测到文件的类型。

magic_numbers = {'png': bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]),
                 'jpg': bytes([0xFF, 0xD8, 0xFF, 0xE0]),
                 #*********************#
                 'doc': bytes([0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]),
                 'xls': bytes([0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]),
                 'ppt': bytes([0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]),
                 #*********************#
                 'docx': bytes([0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00]),
                 'xlsx': bytes([0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00]),
                 'pptx': bytes([0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00]),
                 #*********************#
                 'pdf': bytes([0x25, 0x50, 0x44, 0x46]),
                 #*********************#
                 'dll': bytes([0x4D, 0x5A, 0x90, 0x00]),
                 'exe': bytes([0x4D, 0x5A]),

                 }

max_read_size = max(len(m) for m in magic_numbers.values()) 
 
with open('file.pdf', 'rb') as fd:
    file_head = fd.read(max_read_size)
 
if file_head.startswith(magic_numbers['pdf']):
    print("It's a PDF File")
else:
    print("It's not a PDF file")

我想知道如何在不指定这部分代码的情况下修改它,即一旦我生成或输入文件,它就会直接向我显示文件的类型。

if file_head.startswith(magic_numbers['pdf']):
    print("It's a PDF File")
else:
    print("It's not a PDF file")

希望你能理解我。

【问题讨论】:

  • 那么,您想检查前几个字节而不读取前几个字节?
  • 感谢您的回答,我想从我输入的“幻数”列表中读取内容并从该列表中检测文件类型。没有指定“如果是 PDF,你给我看 PDF”
  • 是的,因此您需要遍历所有元素并测试每个元素。 for 循环为您提供每个键
  • 老实说,我不知道该怎么做。

标签: python header-files detection file-type magic-numbers


【解决方案1】:

您最喜欢只是想遍历循环并测试它们。

您也可以通过使用扩展来优化或提供一些错误检查。如果你去掉扩展名并首先检查,大部分时间你会成功,如果没有,你可能不想接受“baby.png”作为 xlsx 文件。那将是可疑的,值得犯错误。

但是,如果您忽略扩展名,只需遍历条目即可:

for ext in magic_numbers:
    if file_head.startswith(magic_numbers[ext]):
        print("It's a {} File".format(ext))

你可能想把它放在一个返回类型的函数中,所以你可以只返回类型而不是打印出来。

编辑 由于一些共享幻数,我们需要假设扩展是正确的,直到我们知道它不是。我会从文件名中提取扩展名。这可以通过Pathlib 或只是字符串拆分来完成:

ext = filename.rsplit('.', 1)[-1]

那就具体测试一下

if ext in magic_numbers:
    if file_head.startswith(magic_numbers[ext]):
        return ext

把 ext 测试放在第一位,所以把它们放在一起:

ext = filename.rsplit('.', 1)[-1]
if ext in magic_numbers:
    if file_head.startswith(magic_numbers[ext]):
        return ext

for ext in magic_numbers:
    if file_head.startswith(magic_numbers[ext]):
        return ext

return nil

【讨论】:

  • 非常感谢您的回答,这正是我想做的。关于删除扩展名,它返回的正是我想要的,即我知道文件的类型,例如 PDF,当我删除扩展名时,它告诉我它是一个 PDF 文件(你可以测试它)。一个小问题是我们知道 .docx、xlsx 和 pptx 具有相同的“magic_number”。我如何区分它们中的每一个?因为当我使用“.docx”文件运行时,它会显示:* 这是一个 docx 文件 * 这是一个 xlsx 文件 * 这是一个 pptx 文件
  • 对于其他具有相同幻数的扩展也是如此。
  • 如果他们有相同的幻数,你需要回退到扩展。可能是按照我的建议先检查文件扩展名。
  • 如果您真的希望能够在不依赖扩展名的情况下区分各种类型的办公文档(或如何将它们与.zip 文件区分开来),则需要在您使用时进行进一步检查根据Office Open XML standard 检测该幻数。
  • @Garr Godfrey,非常感谢你的建议,但我不明白 :( 我用我的代码试了一下,但没有用。
猜你喜欢
  • 2014-12-09
  • 2020-11-16
  • 2011-08-21
  • 2011-06-17
  • 2015-03-23
  • 1970-01-01
  • 2021-08-18
  • 2010-10-14
  • 2015-09-02
相关资源
最近更新 更多