最近接手了一個項目,接觸到一些對文件操做的業務.因此在這邊整理一下平常用到的處理方式,當學習筆記吧,有不對的地方,歡迎指正哈javascript
首先咱們來看一下 FileReader
這個萬能的對象, 就如同它的名字同樣,就是個文件讀取器, 之因此說它是個萬能的對象是由於它能夠讀取任意格式的內容,最近我嘗試過用 FileReader 讀取過 psd
, ppt
, 各類圖片等等. 雖然不少狀況下,它讀出來的是咱們徹底看不懂的東西.不過經過必定的轉換,理論上咱們能夠在瀏覽器裏面打開任何文件類型.html
下面抄一段 MDN 的文檔前端
FileReader 對象容許Web應用程序異步讀取存儲在用戶計算機上的文件(或原始數據緩衝區)的內容,使用 File 或 Blob 對象指定要讀取的文件或數據.java
其中File對象能夠是來自用戶在一個
<input>
元素上選擇文件後返回的 FileList 對象,也能夠來自拖放操做生成的 DataTransfer 對象,還能夠是來自在一個 HTMLCanvasElement 上執行 mozGetAsFile() 方法後返回結果.node
因爲是抄的,就不作詳細講解,重點是要知道你要讀的文件的編碼類型,而後調用對應的方法取讀就能夠了.這裏有原文git
因爲 FileReader 能夠把文件讀取成各類格式,因此這裏能夠利用這個特性,進行編碼的轉換,如 ArrayBuffer, Blob對象 和 字符串, base64 之間的相互轉換/單向轉換, 部分類型只能單向轉換,是由於 FileReader 只接受 File 或 Blob 類型的數據(事實上 File 也 Blob 的一種),若是數據沒法轉換成指定類型,就沒法用 FileReader 轉換.github
const filereader = new FileReader();
const blob = new Blob(['hello file-reader'], { type: 'text/plain'});
filereader.onload = e => {
console.log(e.target.result); // 輸出 data:text/plain;base64,aGVsbG8gZmlsZS1yZWFkZXI=
}
filereader.readAsDataURL(blob);
複製代碼
網上傳的用 Uint16Array 進行 String 和 ArrayBufer 互轉的其實有編碼長度的問題,我親身體驗過,用 FileReader 就能夠避開這個問題.能夠調用它的 readAsArrayBuffer()
和 readAsText()
方法,把指定對象讀取成 ArrayBuffer 格式 或 純文本格式的數據.web
固然 FileReader 不只僅能用在編碼轉換上,讀取各類文件纔是它主要的能力,配合 <input type="file" >、DataTransfer、Blob 等,能夠把任意格式的數據讀取到瀏覽器裏面.json
上面屢次提到 Blob 對象,私覺得 Blob 也是個很是強大的對象,因此這裏我以爲很是有必要介紹一下,先看看 MDN 怎麼說的數組
Blob 對象表示一個不可變、原始數據的類文件對象.Blob 表示的不必定是JavaScript原生格式的數據.File 接口基於Blob,繼承了 blob 的功能並將其擴展使其支持用戶系統上的文件.
Blob 對象有個同名構造函數,該構造函數接收 2 個參數,第一個參數必須是個 Array 類型的,哪怕你只有一項,也必須用 [ ]
包着,如 ['hello file-reader']
, 第二個參數是個可選的,是個對象,有2個選項,type 和 endings,type 指定第一個參數的 MIME-Type, endings 指定第一個參數的數據格式,其可選值有 transparent(不變,默認) 和 native(隨系統轉換)
const blob = new Blob(['hello file-reader'], { type: 'text/plain'});
複製代碼
Blob.size 能夠獲取對象中所包含數據的大小(字節), Blob.type 能夠獲取對象所包含數據的MIME類型.若是類型未知,則該值爲空字符串.
Blob.slice() 方法能夠返回一個新的 Blob對象,包含了源 Blob對象中指定範圍內的數據, 共接收3個參數,前兩個參數和 Array.slice 的參數相似
參數1:開始索引,默認爲0 參數2:截取結束索引(不包括當前值) 參數3:新Blob的MIME類型,默認爲空字符串
const newBlob = blob.slice(0, 5, 'text/plain');
複製代碼
大文件分段上傳就靠它了,配合 Blob.size 食用,口感更佳哈
經過 URL.createObjectURL(Blob對象), 能夠把 Blob對象 轉換成一個連接地址,該地址能夠直接用在某些 DOM 的 src 或者 href 上, 從而實現前端下載或圖片顯示. 一個比較w神奇的用法是 阮老師的 web worker 教程 裏的「同頁面的 Web Worker」, 這個再配合動態插入 DOM, 是否是就能夠繞開 webworker 的同源策略?
上面提到 FileReader 只能接受 Blob 格式的數據(其餘格式其實也是Blob的子集), 其實 Blob 也只能經過 FileReader 讀取.簡直就是泡麪跟火腿腸,最佳搭檔啊哈
先說說 Arraybuffer 之因此要介紹它,是由於 FileReader 有個 readAsArrayBuffer() 方法,若是的被讀的文件是二進制數據,那用這個方法去讀應該是最合適的,讀出來的數據,就是一個 Arraybuffer 對象,老規矩,看看定義:
ArrayBuffer 對象用來表示通用的、固定長度的原始二進制數據緩衝區.ArrayBuffer 不能直接操做,而是要經過類型數組對象或 DataView 對象來操做,它們會將緩衝區中的數據表示爲特定的格式,並經過這些格式來讀寫緩衝區的內容.
Arraybuffer 也有個同名構造函數,用於建立一個指定長度的,內容所有爲 0 的 ArrayBuffer 對象,構造函數接收一個參數,用來指定要建立的內容長度.如:
let ab = new ArrayBuffer(8); // 建立一個 8 字節的 ArrayBuffer
複製代碼
因爲沒法對 Arraybuffer 直接進行操做,因此咱們須要藉助其餘對象來操做. 全部就有了 TypedArray(類型數組對象)和 DataView.
Int8Array();
Uint8Array();
Uint8ClampedArray();
Int16Array();
Uint16Array();
Int32Array();
Uint32Array();
Float32Array();
Float64Array();
複製代碼
具體用法請參考 MDN: TypedArray
TypedArray 雖然不是真的數組,可是有幾乎跟數組同樣的 API,咱們能夠像操做數組同樣操做 TypedArray ,因此有了 TypedArray 咱們就能夠把 ArrayBuffer 轉換成 TypedArray,而後在進行讀寫操做,達到操做二進制的目的,下面是個例子
let arrayBuffer = new ArrayBuffer(8);
console.log(arrayBuffer[0]); // undefined
let uint8Array = new Uint8Array(arrayBuffer);
console.log(uint8Array); // [0, 0, 0, 0, 0, 0, 0, 0]
uint8Array[0] = 1;
console.log(uint8Array[0]); // 1
console.log(uint8Array); // [1, 0, 0, 0, 0, 0, 0, 0]
複製代碼
能夠看出,用 arrayBuffer[0]
的方式直接獲取 ArrayBuffer 對象的內容是獲取不到的,而 TypedArray 能夠.
直接 console.log(arrayBuffer) 在控制檯是能夠看到
[[Int8Array]] [[Int16Array]] [[Int32Array]] [[Uint8Array]]
4 種 TypedArray 數據,不過這應該是瀏覽器爲了方便開發者觀察數據,而作的轉換,而不是 ArrayBuffer 真的擁有這些數據,畢竟對象名稱看起來也不是那麼正式(用[[]]
包含)
用
arrayBuffer[0] = 1
給 ArrayBuffer 對象的某個下標賦值是不會報錯的,並且稍後你能夠用一樣的路徑取出該值console.log(arrayBuffer[0]) // 1
, 但這並不表明你操做了 ArrayBuffer 的數據,道理跟給數組設置屬性
相同.
let arrayBuffer = new ArrayBuffer(8);
let dataView = new DataView(arrayBuffer);
console.log(dataView.getUint8(1)); // 0
dataView.setUint8(1, 2);
console.log(dataView.getUint8(1)); // 2
console.log(dataView.getUint16(1)); // 512
dataView.setUint16(1, 255);
console.log(dataView.getUint16(1)); // 255
console.log(dataView.getUint8(1)); // 0
複製代碼
就像你看到的,咱們能夠在同一個數據上面,調用不一樣的方法,讀取/寫入 不一樣類型(長度)的數據,可是大部分狀況下,這麼作會很可貴到咱們預期的效果.就像上面的輸出,看起來好像不是那麼的正常,這是由於 一個 16 位的二進制,用 8 位的格式來讀,恰好能夠讀成 2 個 8 位的二進制.舉個栗子
// 16 位的 1
0000 0000 0000 0001
// 用 8 位的讀就變成
0000 0000 // 0
0000 0001 // 1
複製代碼
由於前面 8 位恰好都是 0 , 因此結果看起來除了多個 0 彷佛沒啥區別? 當數字比較大的時候
// 應該是256? 我也不太會算這個
0000 0001 0000 0001
// 用 8 位的讀就變成
0000 0001 // 1
0000 0001 // 1
複製代碼
扯遠了,咱們回頭看看 DataView 提供了哪些方法
// 讀
DataView.prototype.getInt8()
DataView.prototype.getUint8()
DataView.prototype.getInt16()
DataView.prototype.getUint16()
DataView.prototype.getInt32()
DataView.prototype.getUint32()
DataView.prototype.getFloat32()
DataView.prototype.getFloat64()
// 寫
DataView.prototype.setInt8()
DataView.prototype.setUint8()
DataView.prototype.setInt16()
DataView.prototype.setUint16()
DataView.prototype.setInt32()
DataView.prototype.setUint32()
DataView.prototype.setFloat32()
DataView.prototype.setFloat64()
複製代碼
跟 TypedArray 比 少了一個 Uint8ClampedArray() 具體看 MDN: DataView
base64 這個利器,相信前端的你不會陌生吧,最經常使用的操做可能就是圖片轉 base64 了吧? 在以前 要在字符串跟 base64 直接互轉,咱們可能須要去網上拷一個別人的方法,並且大部分狀況下,你沒有時間去驗證這個方法是否是真的可靠,有沒有 bug, 如今咱們能夠直接用內置的方法了
let str = 'I am a string';
let a = btoa(str); // a = 'SSBhbSBhIHN0cmluZw=='
let b = atob(a); // b = 'I am a string'
複製代碼
沒錯,就是這麼簡單,並且大部分瀏覽器都支持 除了 IE9-, 具體能夠參考 CanIUse: atob
btoa 方法不支持中文和特殊字符,因此保險起見,在轉換以前仍是 encodeURIComponent 一下吧, 固然別忘了在 atob 後,再 decodeURIComponent 回來。
最後再安利 3 個包
jspack github.com/pgriess/nod… js操做二進制文件, 咱們的 psd 文件解析就用到這個包.
jszip github.com/Stuk/jszip js操做壓縮文件, 咱們的 pptx 的壓縮比解析成 xml 都靠它.
xml2js github.com/Leonidas-fr… 把 xml 文件轉換成 json, 咱們的 pptx 解析就是用它進行 pptx 的 xml 文件的轉換.
咱們40人的前端團隊常年招兵買馬中,在廈門的和想來廈門的童鞋們,不要吝惜你的簡歷,使勁砸過來 郵箱:atob('bnVveWFAZ2FvZGluZy5jb20=')
, 期待你一塊兒來稿
事