什么是文件魔数(Magic Number)?格式识别原理与常见示例
发布于 2026 年 4 月 24 日 · 阅读约 6 分钟
操作系统怎么知道文件类型?
把一个 PNG 文件改名成 .txt,用 macOS 的 Quick Look 预览,它依然能正确显示图片。在 Linux 上运行 file renamed.txt,输出依然是 PNG image data。文件名明明变了,为什么格式没变?
因为操作系统识别格式从来不靠文件名,而是读取文件开头的几个固定字节——这就是魔数(Magic Number),也叫文件签名(File Signature)。
这套机制是现代操作系统与浏览器的共同基础。
魔数是什么?
每种文件格式在设计时,都会在文件开头预留几个固定字节作为格式声明——这就是魔数(Magic Number),也叫文件签名(File Signature)或文件头(File Header)。
类比一下:你出入境时,海关不需要听你自我介绍,直接翻开护照第一页就能确认国籍。魔数就是文件的「护照首页」——不管文件叫什么名字,打开头几个字节就能确认真实身份。
这也是 Unix file 命令的工作原理:它维护了一份 magic 规则库,通过字节匹配而不是扩展名来判断格式。Windows 资源管理器、macOS Finder、浏览器 MIME 嗅探——底层逻辑都一样。文件类型由内容决定,不由名字决定。
常见格式魔数速查表
以下是开发中最常见格式的文件头签名,均来自实际字节定义:
| 格式 | 魔数(Hex) | 可读形式 | 备注 |
|---|---|---|---|
| PNG | 89 50 4E 47 0D 0A 1A 0A | ‰PNG.... | 8 字节,最易辨认的签名之一 |
| JPEG | FF D8 FF | — | 3 字节,第 3 字节因子类型略有差异 |
| GIF | 47 49 46 38 | GIF8 | 后跟 37(GIF87a)或 39(GIF89a) |
| 25 50 44 46 | %PDF | 后跟版本号,如 -1.7 | |
| WebP | 52 49 46 46 … 57 45 42 50 | RIFF…WEBP | RIFF 容器,需看偏移 8–11 字节 |
| WAV | 52 49 46 46 … 57 41 56 45 | RIFF…WAVE | RIFF 容器,子类型为 WAVE |
| MP3 | 49 44 33 / FF Fx | ID3 / sync | 有 ID3 标签看前 3 字节;无标签时第 2 字节高 3 位为 111 |
| FLAC | 66 4C 61 43 | fLaC | 无损音频,签名清晰 |
| MP4 / MOV / M4A | 00 00 00 xx 66 74 79 70 | ....ftyp | ftyp 容器,需看偏移 8–11 的品牌标识(major brand) |
| WebM | 1A 45 DF A3 | — | EBML 容器头 |
| OGG | 4F 67 67 53 | OggS | 音频/视频 OGG 容器 |
| BMP | 42 4D | BM | Windows 位图 |
陷阱:只看前 4 字节会误判
表格里有两类格式需要特别注意——RIFF 容器和 ftyp 容器。它们的前几个字节相同,但实际上包含完全不同的媒体类型,只看前 4 字节会直接误判。
RIFF 容器(WebP / WAV / AVI)
WebP、WAV、AVI 都以 RIFF(52 49 46 46)开头。真正的子类型藏在偏移 8–11 字节处:
ftyp 容器(MP4 / MOV / M4A)
MP4、MOV、M4A 的开头 4 字节是可变的 box 大小,偏移 4–7 字节固定为 ftyp,偏移 8–11 字节才是品牌码,决定具体格式:
常见品牌码:isom / iso2 / avc1 = MP4,M4A = M4A(Apple 音频),qt = QuickTime MOV。
动手验证:用 file 命令读取魔数
在 macOS 和 Linux 上,file 命令通过读取文件原始字节并与 magic 规则库匹配来识别格式,与文件扩展名无关:
# macOS / Linux
$ file -b photo.png
PNG image data, 617 x 875, 8-bit/color RGBA, non-interlaced
$ file -b photo.txt # 将后缀改为 .txt
PNG image data, 617 x 875, 8-bit/color RGBA, non-interlaced file 是 macOS 和 Linux 的内置工具,Windows 没有原生等价命令。
如果需要在代码里实现相同的格式检测逻辑,核心只需要这几行 JavaScript:
// 取 Base64 字符串前 24 个字符(atob 解码后 = 18 字节),用于格式检测
// (每 4 个 Base64 字符 = 3 字节)
const b64 = "iVBORw0KGgoAAAANSUhEUgAA...";
const bin = atob(b64.slice(0, 24));
const hex = [...bin]
.map(c => c.charCodeAt(0).toString(16).padStart(2, "0"))
.join(" ");
console.log(hex);
// → 89 50 4e 47 0d 0a 1a 0a ...(PNG) 对照速查表:89 50 4e 47 是 PNG,ff d8 ff 是 JPEG,25 50 44 46 是 PDF。
小结
文件类型由二进制头部的魔数决定,与文件名和后缀无关。只要读取开头几个字节并与已知签名对比,就能在没有任何上下文的情况下准确识别格式。
这也是为什么改后缀名骗不过操作系统——也骗不过任何读魔数的工具。
相关文章
优雅地调试 JSON API 响应中的 Base64 图片 →ViewJSON 在渲染 JSON 时会自动对字符串值做魔数检测,Base64 图片、音频和视频直接内联预览。
立即体验
把包含 Base64 内容的 JSON 粘进来,ViewJSON 会自动检测格式,支持图片、音频和视频一键预览。
打开 ViewJSON →