![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5yM0gzNhJWZwQmZhJmNjR2NiFDZ3EDNwAzM4cTM5Y2M38CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
本文首發在我的【個人部落格】
更多豐富的前端學習資料,可以檢視我的 Github: 《Leo-JavaScript》,内容涵蓋資料結構與算法、HTTP、Hybrid、面試題、React、Angular、TypeScript和Webpack等等。 點個 Star 不迷路~
《Leo-JavaScript》https://github.com/pingan8787/Leo-JavaScript
ArrayBuffer 對象與 Blob 對象大家或許不太陌生,常見于檔案上傳操作處理(如處理圖檔上傳預覽等問題)。
那麼本文将與大家深入介紹兩者。
一、ArrayBuffer 對象
ArrayBuffer 對象是 ES6 才納入正式 ECMAScript 規範,是 JavaScript 操作二進制資料的一個接口。ArrayBuffer 對象是以數組的文法處理二進制資料,也稱二進制數組。
介紹 ArrayBuffer 對象還需介紹 TypedArray 視圖和 DataView 視圖,本文不具體介紹,詳細可以檢視阮一峰老師《ECMAScript 6 入門 ArrayBuffer》 章節。
1. 概念介紹
ArrayBuffer 對象代表儲存二進制資料的一段記憶體,它不能直接讀寫,隻能通過視圖(TypedArray視圖和DataView視圖)來讀寫,視圖的作用是以指定格式解讀二進制資料。
關于 TypedArray 視圖和 DataView 視圖 ,可以檢視阮一峰老師《ECMAScript 6 入門 ArrayBuffer》 章節的介紹。
2. 對象使用
浏覽器原生提供 ArrayBuffer() 構造函數,用來生成執行個體。
參數:
- 整數,表示二進制資料占用的位元組長度。
傳回值:
- 一個指定大小的 ArrayBuffer 對象,其内容被初始化為 0。
const buffer = new ArrayBuffer(32);
上面代碼表示執行個體對象 buffer 占用 32 個位元組。
3. 執行個體屬性和方法
ArrayBuffer 對象有執行個體屬性 byteLength ,表示目前執行個體占用的記憶體位元組長度(機關位元組),一單建立就不可變更(隻讀):
const buffer = new ArrayBuffer(32);buffer.byteLength; // 32
ArrayBuffer 對象有執行個體方法 slice(),用來複制一部分記憶體。
參數如下:
- start,整數類型,表示開始複制的位置。預設從 0 開始。
- end,整數類型,表示結束複制的位置(不包括結束的位置)。如果省略,則表示複制到結束。
const buffer = new ArrayBuffer(32);const buffer2 = buffer.slice(0);
4. 相容性
圖檔來自 MDN
二、Blob 對象
1. 概念介紹
Blob 全稱:Binary Large Object (二進制大型對象)。
Blob 對象表示一個二進制檔案的資料内容,通常用來讀寫檔案,比如一個圖檔檔案的内容就可以通過 Blob 對象讀寫。
與 ArrayBuffer 差別:
- Blob 用于操作二進制檔案
- ArrayBuffer 用于操作記憶體
2. 對象使用
浏覽器原生提供 Blob() 構造函數,用來生成執行個體。
Blob 的内容由參數數組中給出的值的串聯組成。
const leoBlob = new Blob(array [, options]);
參數:
- array,必填,成員是字元串或二進制對象,表示新生成的Blob執行個體對象的内容;
成員可以是一個由 ArrayBuffer , ArrayBufferView , Blob , DOMString 等對象構成的 Array ,或者其他類似對象的混合體,它将會被放進 Blob。DOMStrings會被編碼為UTF-8。
- options,可選,是一個配置對象,這裡介紹常用的屬性 type,表示資料的 MIME 類型,預設空字元串;
options 目前可能有兩個屬性: type 和 endings。
endings 用于指定包含行結束符 的字元串如何被寫入,預設值 transparent。它隻有這兩個值:native (代表行結束符會被更改為适合宿主作業系統檔案系統的換行符)和 transparent (代表會保持blob中儲存的結束符不變)。
使用案例:
const leoHtmlFragment = [' hey leo! ']; // 一個包含 DOMString 的數組const leoBlob = new Blob(leoHtmlFragment, {type : 'text/html'}); // 得到 blob
該代碼中,執行個體對象 leoBlob 包含的是字元串。生成執行個體時,指定資料類型為 text/html。
還可以使用 Blob 儲存 JSON 資料:
const obj = { hello: 'leo' };const blob = new Blob([ JSON.stringify(obj) ], {type : 'application/json'});
3. 執行個體屬性和方法
Blob 具有兩個執行個體屬性:
- size:檔案的大小,機關為位元組。
- type:檔案的 MIME 類型。如果類型無法确定,則傳回空字元串。
const leoHtmlFragment = [' hey leo! ']; // 一個包含 DOMString 的數組const leoBlob = new Blob(leoHtmlFragment, {type : 'text/html'}); // 得到 blobleoBlob.size; // 38leoBlob.type; // "text/html"
Blob 執行個體方法:
- clice:方法用于建立一個包含源 Blob 的指定位元組範圍内的資料的新 Blob 對象。
const newBlob = oldBlob.slice([start [, end [, contentType]]])
包含三個參數:
start,可選,起始的位元組位置,預設 0;
end,可選,結束的位元組位置,預設 size 屬性的值,不包含該位置;
contentType,可選,新執行個體的資料類型(預設為空字元串);
4. 相容性
圖檔來自 MDN
5. 實際案例
5.1 擷取檔案資訊
檔案選擇器 用來讓使用者選取檔案。出于安全考慮,浏覽器不允許腳本自行設定這個控件的 value 屬性,即檔案必須是使用者手動選取的,不能是腳本指定的。一旦使用者選好了檔案,腳本就可以讀取這個檔案。
檔案選擇器傳回一個 FileList 對象,該對象是個類數組對象,每個成員都是一個 File 執行個體對象。File 執行個體對象是一個特殊的 Blob 執行個體,增加了 name 和 lastModifiedDate 屬性。
也包括拖放 API 的 dataTransfer.files 傳回的也是一個 FileList 對象,成員也是 File 執行個體對象。
// HTML 代碼如下// function fileinfo(files) { for (let i = 0; i < files.length; i++) { let f = files[i]; console.log( f.name, // 檔案名,不含路徑 f.size, // 檔案大小,Blob 執行個體屬性 f.type, // 檔案類型,Blob 執行個體屬性 f.lastModifiedDate // 檔案的最後修改時間 ); }}
5.2 下載下傳檔案
在 AJAX 請求中,指定 responseType 屬性為 blob ,皆可以下下載下傳一個 Blob 對象。
function getBlob(url, callback) { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'blob'; xhr.onload = function () { callback(xhr.response); } xhr.send(null);}
然後,xhr.response 拿到的就是一個 Blob 對象。
5.3 生成 URL
浏覽器允許使用 URL.createObjectURL() 方法,針對 Blob 對象生成一個臨時URL,以便于某些 API 使用。
如作為圖檔預覽的 URL。
這個 URL 以 blob:// 開頭,表明對應一個 Blob 對象,協定頭後面是一個識别符,用來唯一對應記憶體裡面的 Blob 對象。這一點與 data://URL(URL 包含實際資料)和 file://URL(本地檔案系統裡面的檔案)都不一樣。
const droptarget = document.getElementById('droptarget');droptarget.ondrop = function (e) { const files = e.dataTransfer.files; for (let i = 0; i < files.length; i++) { let type = files[i].type; if (type.substring(0,6) !== 'image/') continue; let img = document.createElement('img'); img.src = URL.createObjectURL(files[i]); img.onload = function () { this.width = 100; document.body.appendChild(this); URL.revokeObjectURL(this.src); } }}
代碼中,通過為拖放的圖檔檔案生成一個 URL,作為預覽的縮略圖。
浏覽器處理 Blob URL 就跟普通的 URL 一樣,如果 Blob 對象不存在,傳回404狀态碼;如果跨域請求,傳回403狀态碼。Blob URL 隻對 GET 請求有效,如果請求成功,傳回200狀态碼。由于 Blob URL 就是普通 URL,是以可以下載下傳。
5.4 讀取檔案
取得 Blob 對象以後,可以通過 FileReader 對象,讀取 Blob 對象的内容,即檔案内容。
FileReader 對象提供四個方法。将 Blob 對象作為參數傳入,然後以指定的格式傳回。
- FileReader.readAsText():傳回文本,需要指定文本編碼,預設為 UTF-8。
- FileReader.readAsArrayBuffer():傳回 ArrayBuffer 對象。
- FileReader.readAsDataURL():傳回 Data URL。
- FileReader.readAsBinaryString():傳回原始的二進制字元串。
下面是 FileReader.readAsText() 方法的例子,用來讀取文本檔案:
// HTML 代碼如下// //
function readfile(f) { let reader = new FileReader(); reader.readAsText(f); reader.onload = function () { let text = reader.result; let out = document.getElementById('output'); out.innerHTML = ''; out.appendChild(document.createTextNode(text)); } reader.onerror = function(e) { console.log('Error', e); };}
下面是 FileReader.readAsArrayBuffer() 方法的例子,用于讀取二進制檔案:
// HTML 代碼如下// function typefile(file) { // 檔案開頭的四個位元組,生成一個 Blob 對象 let slice = file.slice(0, 4); let reader = new FileReader(); // 讀取這四個位元組 reader.readAsArrayBuffer(slice); reader.onload = function (e) { let buffer = reader.result; // 将這四個位元組的内容,視作一個32位整數 let view = new DataView(buffer); let magic = view.getUint32(0, false); // 根據檔案的前四個位元組,判斷它的類型 switch(magic) { case 0x89504E47: file.verified_type = 'image/png'; break; case 0x47494638: file.verified_type = 'image/gif'; break; case 0x25504446: file.verified_type = 'application/pdf'; break; case 0x504b0304: file.verified_type = 'application/zip'; break; } console.log(file.name, file.verified_type); };}
三、參考資料
- 《ArrayBuffer 對象,Blob 對象》
- 《ECMAScript 6 入門 ArrayBuffer》