前言
一般情况下我们判断一个文件是什么类型都是通过看它的后缀名,例如 xx.mp3
xx.mp4
xx.jpg
,但是这并不准确!
假如我把 xx.wav
文件的后缀手动改成了 .mp3
,但它的文件类型依旧是 wav,因为计算机是通过读取文件二进制的前几个字节来区分文件类型,
对于大多数类型的文件,起始字节都是固定的,这些字节通常被称为 “魔数” (Magic Number)
常见文件的“魔数”
- JPEG 图片:
FF D8 FF DB
|49 46 00 01
… - PNG 图片:
89 50 4E 47 0D 0A 1A 0A
… - MP3 音频:
49 44 33
|FF FB
|FF F3
|FF F2
… - MP4 视频:
66 74 79 70 69 73 6F 6D
…
更多请参考 维基百科 - List of file signatures
读取文件二进制数据
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = (e) => {
// 这里就拿到了文件的二进制数据
const arrBuffer = e.target.result as ArrayBuffer;
};
reader.onerror = (err) => {
throw new Error(err);
};
二进制数组 转 16 进制字符串
这里有个需要注意的地方,如果文件太大了,导致二进制数组长度超过 2^32,
使用 Array.form 方法转换时候会报错invalid array length
。
详情可参考:MDN - invalid array length
function bufferToString(buffer: ArrayBuffer) {
const uint8Array = new Uint8Array(buffer, 0, Math.pow(2, 16));
return Array.from(uint8Array)
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
}
类型判断
最后通过正则去匹配字符串开头是否包含对于文件的“魔数”。
const Mp3MagicNum = ["494433", "FFE2", "FFE3", "FFF2", "FFF3", "FFFA", "FFFB"];
function isMp3Type(hex: string) {
for (let key of this.Mp3MagicNum) {
if (new RegExp("^" + key, "i").test(hex)) return true;
}
return false;
}
const hex = bufferToString(arrBuffer);
const isMp3 = isMp3Type(hex);