js获取文件真实类型

1. 方法简介

方法一:
最简单的就是直接获取文件后缀,但是如果后缀不准确,被人为修改就会出现识别错误
方法二:
直接读取文件二进制信息头部获取类型。

2. 实现

2.1 原理

在计算机里面,所有文件本质都是一对二进制数据,而各种文件类型除了给用户看的后缀用以区分,本身二进制数据里面也有用于区分类型的数据。大部分文件二进制头部都有用于区分其类型的一串特征编码,也就是一串神奇数字。
比如png头部前8个字节是0x89504E470D0A1A0A,我们只要读取出前八个字节就可以基本上确定这就是一个png无论你把它后缀改成什么。(字节数搞不清楚的可以单独去网上查一下,简单说一下,这里是16进制,大部分计算机4位等于116进制,8位为1字节,所以这里有1616进制也就是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 总结

  1. 大部分时候直接判断后缀就行了,如果需要严格判断就可以使用这种方法
  2. 最好使用8位的转化方法,防止某些平台字节序的不同导致判断失败
  3. 文件类型编码
  4. 注意wps另存为的docxofficedocx编码不一样,wps的代码是[0x50, 0x4B, 0x03, 0x04, 0x0A]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容