使用 Files.newInputStream() 读取文件头字节,依据 Magic Number 快速识别媒体类型:JPEG 读4字节、PNG 读8字节、GIF 读6字节、MP4/MOV 读12字节、AVI 读12字节,配合 readNBytes 和预定义签名数组高效校验。
用 files.newinputstream() 读取大型媒体文件的二进制头信息,核心是「只读开头少量字节」,避免加载整个文件。java 的 inputstream 天然支持按需读取,配合标准文件头(magic number)比对,就能快速、低开销地校验真实类型。
明确要读多少字节:不同格式的 Magic Number 长度不同
媒体文件的真实类型识别依赖其文件头(前几个字节),常见格式所需最小读取长度如下:
-
JPEG:以
0xFF 0xD8开头,通常读前 4 字节即可确认(含 SOI + APP0 标记) -
PNG:固定为 8 字节签名
89 4E 47 0D 0A 1A 0A -
GIF:前 6 字节为
47 49 46 38 37 61或47 49 46 38 39 61(即 "GIF87a" 或 "GIF89a") -
MP4 / MOV:前 4 字节是 box size,接着 4 字节是 type(如
ftyp),一般读前 12 字节可定位 -
AVI:第 9–12 字节为
41 56 49 20("AVI "),需至少读 12 字节
用 try-with-resources 安全打开并限制读取长度
直接调用 Files.newInputStream(path) 返回一个可重复读取的流(注意不是所有实现都支持 mark/reset,但本地文件系统通常支持)。推荐用 InputStream.readNBytes(int)(Java 11+)或手动循环读取指定字节数:
Path path = Paths.get("video.avi");
byte[] header = new byte[12]; // 按需调整长度
try (InputStream is = Files.newInputStream(path)) {
int read = is.readNBytes(header, 0, header.length);
if (read < header.length) {
throw new IOException("文件太短,无法识别类型");
}
}
// 接着解析 header 数组
⚠️ 注意:readNBytes 会阻塞直到读满或流结束,适合小头部;若需兼容 Java 8,可用 is.read(byte[], off, len) 并检查返回值是否等于预期长度。
比对 Magic Number:用字节数组硬匹配或工具类辅助
不依赖第三方库时,直接用 Arrays.equals() 比较字节片段。例如判断是否为 PNG:
private static boolean isPng(byte[] header) {
return header.length >= 8 &&
header[0] == (byte) 0x89 &&
header[1] == (byte) 0x4E &&
header[2] == (byte) 0x47 &&
header[3] == (byte) 0x0D &&
header[4] == (byte) 0x0A &&
header[5] == (byte) 0x1A &&
header[6] == (byte) 0x0A;
}
更简洁的方式是预定义常量数组:
private static final byte[] PNG_SIGNATURE = {(byte)0x89, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
// ...
if (header.length >= PNG_SIGNATURE.length &&
Arrays.equals(header, 0, PNG_SIGNATURE.length, PNG_SIGNATURE, 0, PNG_SIGNATURE.length)) {
return "image/png";
}
补充建议:处理边界与可靠性提升
仅靠文件头识别有局限,实际中可叠加简单策略提高鲁棒性:
- 对 MP4 类容器,先找
ftypbox,它可能不在绝对开头(存在自定义 box),此时需简单解析前若干个 box 头(每个 box 含 4 字节 size + 4 字节 type) - 若文件扩展名与头信息冲突(如 .jpg 文件实际是 PNG),优先信头部 —— 这正是校验的目的
- 对超大文件(如 10GB 视频),确保不触发 GC 压力:header 缓冲区始终是固定小数组(
- 如需更高精度(如区分 H.264/H.265 编码),需进一步解析 moov/trak box,但已超出「头部校验」范畴


















