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位的轉化方法,防止某些平臺字節序的不同導致判斷失敗
- 文件類型編碼
- 注意
wps
另存為的docx
和office
的docx
編碼不一樣,wps
的代碼是[0x50, 0x4B, 0x03, 0x04, 0x0A]