天天看點

arraybuffer mime_「前端知乎系列」ArrayBuffer 和 Blob 對象

arraybuffer mime_「前端知乎系列」ArrayBuffer 和 Blob 對象

本文首發在我的【個人部落格】

更多豐富的前端學習資料,可以檢視我的 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. 相容性

arraybuffer mime_「前端知乎系列」ArrayBuffer 和 Blob 對象

圖檔來自 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. 相容性

arraybuffer mime_「前端知乎系列」ArrayBuffer 和 Blob 對象

圖檔來自 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);  };}
           

三、參考資料

  1. 《ArrayBuffer 對象,Blob 對象》
  2. 《ECMAScript 6 入門 ArrayBuffer》

繼續閱讀