用 fread 读前8字节二进制内容,直接 memcmp 比对 Magic Number(如 "fLaC"、"RIFF"),避免字符串转换;MP4/HEIC 需检查 offset 4 处的 "ftyp";优先用 std::ifstream binary 模式,兼顾安全与效率。

怎么用 fread 读前几个字节判断文件类型
直接读取文件开头固定长度(通常 4–16 字节),比扩展名或后缀靠谱得多——很多资源根本没后缀,或者被改过。关键不是“读多少”,而是“读完立刻比较”,别用 std::string 包一层再比,容易引入空字符截断或编码干扰。
实操建议:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 用
std::ifstream以std::ios::binary模式打开,避免换行符转换干扰 - 优先读 8 字节:够覆盖
MP4("ftyp")、AVI("RIFF")、FLAC("fLaC")、WAV("RIFF")等常见格式的 Magic Number - 读完立刻用
memcmp或std::equal比字节序列,别转成 C 字符串再用strcmp——二进制里可能含\0 - 注意字节序:Magic Number 是大端约定的,比如
PDF是"%PDF"(ASCII 文本),而ELF是"\x7fELF",不能按整数解析
libmagic 在 C++ 里怎么轻量调用不踩坑
系统自带的 file 命令底层就是 libmagic,它比手写判断表更全,但直接链 libmagic 容易漏掉数据库路径或初始化失败,导致始终返回 "data"。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 必须显式调用
magic_open(MAGIC_MIME_TYPE | MAGIC_NO_CHECK_COMPRESS),否则默认只返回描述文本,且可能误判压缩包 - 用
magic_load(magic_cookie, "/usr/share/misc/magic.mgc")指定编译好的数据库路径;Ubuntu 是/usr/share/file/magic.mgc,macOS(brew)是/opt/homebrew/share/misc/magic.mgc,别硬编码 - 调用
magic_file()前确保文件已seekg(0)回头,否则可能读到空内容 - 返回值是
const char*,但它指向内部缓冲区,不用free,但下一次magic_file()调用会覆盖——要保留就得strdup
常见多媒体格式 Magic Number 对照和易错点
不是所有格式都靠前 4 字节唯一识别,有些得看偏移+长度组合,比如 MP4 的 "ftyp" 在 offset 4,而 PNG 的 "\x89PNG" 在 offset 0 —— 直接 memcmp 前 4 字节会把 PNG 判成未知。
典型 Magic Number 和陷阱:
-
MP4 / MOV:实际是ftypbox,位于 offset 4,前 4 字节是 size(大端 uint32),所以得先读 8 字节,再检查buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p' -
AVI / WAV:都是"RIFF"开头,得继续读第 8–12 字节(FourCC)区分:AVIvsWAVE(注意空格) -
FLAC:固定 4 字节"fLaC",但有些封装在 Ogg 容器里,开头是"OggS",这时得进一步解析 Ogg page header -
HEIC / HEIF:Magic 是"ftypmsf1"或"ftypheic",但同样在 offset 4,且依赖后续 type 字段,不能只看前 4
性能敏感场景下要不要 mmap + 指针比对
如果要批量识别上万个小资源(比如游戏 asset 扫描),fread 每次开闭文件确实有开销,但 mmap 并不总是更快——小文件 mmap 反而增加 TLB 压力,且跨平台清理麻烦(Windows 用 CreateFileMapping,Linux 用 mmap)。
更实际的做法:
- 单次识别:坚持用
fread+ 8 字节栈缓冲,简单、安全、无内存泄漏风险 - 高频批量识别:把文件描述符缓存住,用
lseek(fd, 0, SEEK_SET)+read(fd, buf, 8),跳过 C 库 FILE* 层开销 - 真要 mmap:只对 >64KB 的文件考虑,且必须用
MAP_PRIVATE | MAP_POPULATE预加载,否则第一次访问页错误反而更慢 - 永远不要假设文件可读——
open()或fopen()失败、权限不足、NFS timeout 都得兜底返回"unknown"
最常被忽略的是:Magic Number 只能排除,不能 100% 确认。一个伪造的 "RIFF" 开头文件可能是恶意 payload,业务层仍需后续校验结构合法性。


















