python-magic:最实用的文件内容识别方法,取代扩展名

当服务器具备图片上传功能时,往往会遇到以下需求。

  • .png上传了…真的 PNG 吗?”
  • “先判断文件是图片还是文档再分流。”
  • “在使用外部解析器(Pillow/OpenCV)之前,至少先确认类型。”

此时最稳妥的起点不是扩展名,而是文件内容。而实现“基于内容识别”最简便的工具就是 python-magic


python-magic 是什么?



python-magic 是一个 Python 包,它封装了 C 语言库 libmagic。libmagic 通过检查文件的头部(前几字节)等特征来识别文件类型。类似的功能在 Unix 的 file 命令中也能找到。

简而言之:

  • file(Linux 命令)= “终端使用的接口”
  • libmagic = “核心引擎(识别逻辑)”
  • python-magic = “Python 调用 libmagic 的薄封装”

本文将围绕 python-magic,结构化地说明“这个引擎究竟是如何识别文件类型的”。


核心引擎(libmagic)是如何工作的?

libmagic 库工作原理图

libmagic 的本质很简单:

“读取包含文件类型识别规则的数据库,按规则检查文件字节,给出最合理的结论。”

这里的数据库即为 magic database(magic 数据库),供 file/libmagic 一起使用。通常以编译后的形式(magic.mgc)安装在系统中。

1) “魔法文件”是规则集合

这些规则基本由以下几部分组成:

  • 查看位置(offset:文件的哪一字节)
  • 读取方式(type:字节/字符串/整数等)
  • 比较值(expected value/pattern)
  • 输出结果(message/MIME 等)

file 的手册也说明它在检查 magic patterns。规则逐行测试(offset/type/value/message),若匹配则进入更具体的子测试,形成层级结构。

想了解 Linux file 命令的细节,请点击以下链接。

了解 Linux file 命令

2) 规则数据库有“文本原始”和“编译结果”两种形式

魔法数据库最初是人可读的文本片段集合,为了性能,通常也提供编译后的二进制数据库(.mgc)。

3) 最终目标是“看文件内容而非扩展名”

file 之所以被视为“内容型类型推断器”已有悠久历史。python-magic 就是把这一哲学用“一行 Python 代码”实现的工具。


如何使用 python-magic?



常见的使用模式有两种。

1) 以 MIME 类型获取(最实用)

适用于上传处理、路由、日志/指标等。

import magic

mime = magic.from_file("upload.bin", mime=True)
print(mime)  # 例如: image/png

python-magic 基于 libmagic 提供文件类型识别功能,官方说明与 file 命令同属一类。

2) 直接以 bytes 进行识别(上传流更友好)

在将文件写入磁盘之前,想先快速查看上传的字节片段时非常有用。

import magic

with open("upload.bin", "rb") as f:
    head = f.read(4096)

mime = magic.from_buffer(head, mime=True)
print(mime)

(基于缓冲区的识别是“文件保存前的第一道过滤器”)


开发者视角:在哪些场景下有用?

1) 上传验证的第一道防线

  • 不仅凭扩展名做分流
  • 至少确认“是否可以作为图片处理”

2) 处理管道的分流点

  • 若是图片,则进入缩放/缩略图管道
  • 若是 PDF/ZIP,则交给其他工作者
  • 若是未知类型,则隔离/拒绝/进一步验证

3) 在调用“重量级解码器”之前降低成本

Pillow 等解码器功能强大,但调用本身会增加内存/CPU/攻击面。python-magic 可以在此之前判断“是否值得继续处理”。

重要的现实检查:libmagic 仅是 推断/识别 工具。若目标是安全完整的判定(拦截恶意负载等),仍需额外验证(白名单、大小限制、沙箱解码等)。


结语:python-magic 是“把文件类型识别带到代码中的最轻量方式”

python-magic 并不提供图片处理本身,而是快速告诉你“该文件应被视为哪种类型”。

  • 引擎:file 同类的 libmagic
  • 识别方式:规则数据库 + 字节检查
  • 开发实战:上传验证、路由、成本节约尤为适用

掌握它后,即使在库不足的环境中,也能构建“识别 → 分流 → 安全防护”的完整流程。


下期预告

  • Pillow(PIL)的 open()load()verify() 各自保证什么,何时使用,如何工作,做一份整理。

相关阅读