1. 方法简介
方法一:
最简单的就是直接获取文件后缀,但是如果后缀不准确,被人为修改就会出现识别错误
方法二:
直接读取文件二进制信息头部获取类型。
2. 实现
2.1 原理
在计算机里面,所有文件本质都是一对二进制数据,而各种文件类型除了给用户看的后缀用以区分,本身二进制数据里面也有用于区分类型的数据。大部分文件二进制头部都有用于区分其类型的一串特征编码,也就是一串神奇数字。
比如png
头部前8个字节是0x89504E470D0A1A0A
,我们只要读取出前八个字节就可以基本上确定这就是一个png
无论你把它后缀改成什么。(字节数搞不清楚的可以单独去网上查一下,简单说一下,这里是16
进制,大部分计算机4
位等于1
位16
进制,8
位为1
字节,所以这里有16
个16
进制也就是8
个字节)
2.2 TypedArray
实现
<input id='file' type="file"/>
<script>
// 输入事件
document.getElementById('file').onchange = function (e) {
// 获取文件
const file = this.files[0]
// 读取文件二进制内容
// arrayBuffer存储的是字节为单位的数据
// arrayBuffer直接是不能做什么操作的,所以要转换一下
file.arrayBuffer()
.then(arrayBuffer => {
// 二进制转化为数字
// 先提取头部8个字节
// 后面我们要每8位转化成一个数字
// 你用Uint16Array也可以,但是不大好比较,因为大部分计算机的字节序都是小端,所以每一段顺序是反的,不好比较
const flieUnit8Array = new Uint8Array(arrayBuffer.slice(0, 8))
// 输出一个类似数组的 [ 137, 80, 78, 71, 13, 10, 26, 10 ]
// 你可以试一试Uint16Array,你会发现顺序反了 [ "5089", "474e", "a0d", "a1a" ]
const checkList = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
// 对位比较就行了
console.log(unit8.every((v, index) => v === checkList[index]))
})
}
</script>
2.3 DataView
实现
<input id='file' type="file"/>
<script>
document.getElementById('file').onchange = function (e) {
const file = this.files[0]
file.arrayBuffer()
.then(arrayBuffer => {
// 前面都是一样的,这里我们把arrayBuffer 转成dataView
// dataView仍然是一堆字节
const dataView = new DataView(arrayBuffer.slice(0, 8))
// 接下来不需要转化成数字,直接调用dataview的方法就行了
const checkList = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
checkList.every((v, index) => v === dataView.getUint8(index)) // true
// 这里不同的是我们取16位的整数顺序正确了
['0x8950', '0x4e47', '0xd0a', '1a0a'].every((v, index) => v === dataView.getUint16(index)) // true
})
}
</script>
3 总结
- 大部分时候直接判断后缀就行了,如果需要严格判断就可以使用这种方法
- 最好使用8位的转化方法,防止某些平台字节序的不同导致判断失败
网友评论