Java中通过字节流读取文件前N字节比对魔数可轻量可靠识别类型:用FileInputStream配合try-with-resources读取,检查返回长度,用Arrays.equals逐个匹配预定义魔数(如PNG为8字节、JPEG为2字节),优先长魔数,返回Optional类型名。

Java 中用字节流读取文件前几个字节,比对预定义的魔数(Magic Number),是轻量、可靠识别文件类型的方式,不依赖扩展名或系统命令。
读取文件前 N 个字节
使用 FileInputStream 打开文件,调用 read(byte[] b, int off, int len) 读取指定长度(如 4 字节)到字节数组。注意检查返回值是否等于预期长度,避免 EOF 提前发生。
- 魔数长度常见为 2~8 字节(如 PNG 是 8 字节
89 50 4E 47 0D 0A 1A 0A,JPEG 是 2 字节FF D8) - 务必用 try-with-resources 确保流关闭
- 读取失败或长度不足时应视为“无法识别”而非抛异常
定义常见魔数映射表
用 Map<byte string></byte> 或更推荐的 Map<list>, String></list>(便于调试),但实际中建议用静态常量 + if/else 或 switch(Java 17+ 支持 byte[] case 需编译器支持,稳妥起见仍用 Arrays.equals())。
例如:
立即学习“Java免费学习笔记(深入)”;
PNG: { (byte)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }JPEG: { (byte)0xFF, 0xD8 }
GIF: { 0x47, 0x49, 0x46 } (即 "GIF" ASCII)
PDF: { 0x25, 0x50, 0x44, 0x46 } (即 "%PDF")
比对与识别逻辑
将读出的字节数组与各魔数逐个用 Arrays.equals(header, MAGIC_PNG) 判断。注意字节顺序严格匹配,高位在前(Big-Endian),无需反转。
- 优先匹配更长的魔数(如先试 PNG 的 8 字节,再试 GIF 的 3 字节),避免短魔数误触发
- 区分大小写:文本类魔数(如 PDF、ZIP)按 ASCII 值比较,不是字符串 equals
- ZIP 和 DOCX/EPUB/XLSX 等同属 ZIP 格式,魔数都是
50 4B 03 04,可统一返回 "zip"
封装成可复用方法
写一个静态工具方法,入参为 Path 或 File,返回 Optional<string></string> 类型名(如 "png"、"jpeg"),未识别则为空。内部处理异常、流关闭、边界情况(文件太小、权限拒绝等)。
示例关键片段:
byte[] header = new byte[8];int read = fis.read(header);
if (read if (Arrays.equals(Arrays.copyOf(header, 2), JPEG_MAGIC)) return Optional.of("jpeg");
if (Arrays.equals(Arrays.copyOf(header, 8), PNG_MAGIC)) return Optional.of("png");


















