File、Blob、ArrayBuffer等文件類的對象有什么區別和聯系


前言

在前端中處理文件時會經常遇到File、Blob、ArrayBuffer以及相關的處理方法或方式如FileReader、FormData等等這些名詞,對於這些常見而又不常見的名詞,我相信大多數人對它們都有一種熟悉的陌生人的感覺。究其原因,相關的東西接觸的不夠多,且每次都網上隨手拈來,不求甚解。今天,我們就稍微仔細一點,去做一個探究,弄清他們是誰,能做什么,又有什么區別,爭取下次再見既是“老朋友”。如果,你想更深入的了解相關知識點,可以參閱w3c和MDN的解釋,文后會附上相關的參考鏈接供參考。

內容

File

定義/概念

File即我們通常所說的文件,我們硬盤里存儲的音視頻、文檔等等都是文件。我們通常使用<input type="file">來選取並讀取本地計算機中的文件,返回一個Filelist對象,此對象為一個類數組可迭代對象。File對象是特殊類型的Blob,所以順便也繼承了Blob特有的方法和屬性,同時又有自己獨特的屬性和方法。

MDN定義:文件(File)接口提供有關文件的信息,並允許網頁中的 JavaScript 訪問其內容。通常情況下, File 對象是來自用戶在一個 <input> 元素上選擇文件后返回的 FileList 對象,也可以是來自由拖放操作生成的 DataTransfer 對象,或者來自 HTMLCanvasElement 上的 mozGetAsFile() API。

用法/示例

File常用的屬性有:

File.name 只讀,返回當前File 對象所引用文件的名稱。

File.size 只讀,返回當前File 對象文件的大小。

File.type 只讀,返回文件的多用途互聯網郵件擴展類型(MIME Type)

更多屬性及方法信息可參考MDN,這里就不再詳細贅述。

FileList: <input type="file"> 元素有一個files屬性,用來存儲用戶所選擇的文件,當用戶點擊選擇文件按鈕之后,便可以獲取到選擇的文件組成的FileList對象。

1
2
const fileList = document.getElementById('file').files;
console.log(fileList);
 

結果

在這幾個當中,File應該是我們使用的頻率最高的一個,應該也是最熟悉的一個,所以過多的內容這里就不一一示例。這里引入一個很久之前遇到的一個相關的IE兼容性問題。

input[type=file]這個文件上傳原生按鈕不夠美觀,通常都是采取隱藏此原生的按鈕,使用另外一個自定義的按鈕,然后,通過點擊此按鈕間接觸發隱藏的原生按鈕,從而實現這一功能。但是,由於IE安全限制,我們間接通過clik()觸發的,在IE9某些版本就會報SCRIPT: 拒絕訪問的錯誤。解決這個問題,要主動觸發上傳按鈕,此時借助label的for屬性,綁定到對應的input上即可解決此問題。

Blob

定義/概念

Blob是Binary Large Object的縮寫,表示二進制大對象,它並不是前端的所特有對象,而是計算機界的通用術語,在一些數據庫中,例如,MYSQL中的BLOB類型就表示二進制數據的容器。MDN上對其的定義是:Blob 對象表示一個不可變、原始數據的類文件對象。可以通俗的說,Blob就是一只讀的二進制對象。從File的介紹我們已知File繼承自Blob,有許多相同的方法和屬性,因此可以像操作File對象一樣操作Blob對象。

用法/示例

Blob主要包含兩個屬性

  • Blob.size:只讀,對象中所包含數據的大小(字節)
  • Blob.type:只讀,一個字符串,表明該 Blob 對象所包含數據的 MIME 類型。如果類型未知,則該值為空字符串。(MIME類型參考

創建一個Blob對象,需要調用Blob構造函數。

1
2
3
4
5
/**
* @param {Array} array 一個由ArrayBuffer, ArrayBufferView, Blob, DOMString 等對象構成的數組
* @param {Object} options 一個可選的BlobPropertyBag字典
*/
function Blob( array, options ){};
 

array 是一個由ArrayBufferArrayBufferViewBlobDOMString 等對象構成的 Array ,或者其他類似對象的混合體,它將會被放進 BlobDOMStrings會被編碼為UTF-8。

options 是一個可選的BlobPropertyBag字典,它可能會指定如下兩個屬性:

  • type,默認值為 "",它代表了將會被放入到blob中的數組內容的MIME類型。
  • endings,默認值為"transparent",用於指定包含行結束符\n的字符串如何被寫入。 它是以下兩個值中的一個: "native",代表行結束符會被更改為適合宿主操作系統文件系統的換行符,或者 "transparent",代表會保持blob中保存的結束符不變

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const data1 = "a";
const data2 = "b";
const data3 = "<div style='color:red;'>This is a blob</div>";
const data4 = { "name": "abc" };
// 創建blob對象
const blob1 = new Blob([data1]);
const blob2 = new Blob([data1, data2]);
const blob3 = new Blob([data3], {type : 'text/html'});
const blob4 = new Blob([JSON.stringify(data4)]);
const blob5 = new Blob([data4]);
const blob6 = new Blob([data3, data4]);

console.log(blob1); //輸出:Blob {size: 1, type: ""}
console.log(blob2); //輸出:Blob {size: 2, type: ""}
console.log(blob3); //輸出:Blob {size: 44, type: "text/html"}
console.log(blob4); //輸出:Blob {size: 14, type: ""}
console.log(blob5); //輸出:Blob {size: 15, type: ""}
console.log(blob6); //輸出:Blob {size: 59, type: ""}
 

以上blob5的size值打印為什么是15呢?原因是,當使用普通對象創建Blob對象時,相當於調用了普通對象的toString()方法得到字符串數據,然后再創建Blob對象。所以,blob5保存的數據是"[object Object]",是15個字節(不包含最外層的引號)。

Blob目前有四個方法:

Blob.slice([start[, end[, contentType]]]):返回一個新的 Blob 對象,包含了源 Blob 對象中指定范圍內的數據。(由於File繼承自Blob,可用此方法分割本地文件,實現分片上傳)

Blob.stream():返回一個能讀取blob內容的 ReadableStream

Blob.text():返回一個promise且包含blob所有內容的UTF-8格式的 USVString

Blob.arrayBuffer():返回一個promise且包含blob所有內容的二進制格式的 ArrayBuffer

ArrayBuffer

定義/概念

你從XHR、File API、Canvas等等各種地方,讀取了一大串字節流,如果用JS里的Array去存,又浪費,又低效。
於是為了配合這些新的API增強JS的二進制處理能力,就有了ArrayBuffer。

ArrayBuffer簡單說就是一片內存,表示原始二進制數據緩沖區。但不能直接操作它,而是要通過類型數組對象TypedArray或 DataView (數據視圖)對象來操作它,它們會將緩沖區中的數據表示為特定的格式,並通過這些格式來讀寫緩沖區的內容。TypedArrayArrayBuffer提供了一個“View”,對它們進行下標讀寫。也可以使用DataView來讀寫ArrayBufferDataView能更自由的選擇字節序,不用考慮不同平台的字節序問題。

MDN將ArrayBuffer 對象定義為用來表示通用的、固定長度的原始二進制數據緩沖區。它是一個字節數組,通常在其他語言中稱為“byte array”。

用法示例

由於ArrayBuffer不能直接進行操作,故需要借助TypedArray或者DataView來進行讀寫。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 生成一個可以16個字節的連續內存,每個字節的默認值是0
const buffer = new ArrayBuffer(16);

// TypedArray 使用標准數組語法來獲取和設置屬性值
var int16 = new Int16Array(2);
int16[0] = 42;
console.log(int16[0]); // 42

const buffer = new ArrayBuffer(16);
const a = new Uint8Array(buffer); // 建立Uint8Array視圖
const b = new Int32Array(buffer); // 建立Int32Array視圖
a[0] = 1;
b[0] = 2;
// 由於兩個視圖是對應的是同一段內存,所以其中一個視圖更改了內存,會影響到另一個視圖
a[0]; // 2
 

結語

區別/聯系

File和Blob
  • 相同點: File和Blob都可以用來表示類文件對象,處理文件;

  • FIle: File可以看作一個承載文件的橋梁,將DOM接口和文件聯系起來,通過File這個橋梁,獲取計算及內的文件,從而對才能對文件做進一步處理。

  • Blob:File繼承自Blob,他們之間很方便進行轉換,Blob是File都原型對象。

  • 聯系:File繼承自Blob,同時又有自己獨特的屬性和方法。從下面的打印可以看出,其實Blob對象就是File的原型對象,自然就擁有了Blob對象的方法和屬性。

    1
    <input type="file" id="myfiles" />
     
    1
    2
    3
    4
    5
    6
    7
    const fileDOM = document.querySelector("#myfiles");
    const fileChange = (e) => {
    const files = fileDOM.files;
    console.log(files[0].__proto__) // 輸出File
    console.log(files[0].__proto__.__proto__) // 輸出Blob
    }
    fileDOM.onchange = fileChange;
     
Blob與ArrayBuffer
  • 相同點: BlobArrayBuffer都是二進制的容器。

  • ArrayBuffer:ArrayBuffer更底層,是一段純粹的內存上的二進制數據,我們可以對其任何一個字節進行單獨的修改,也可以根據我們的需要以我們指定的形式讀取指定范圍的數據。

  • Blob:Blob就是將二進制數據做了一個封裝,我們拿到的就是一個整體,可以看到它的整體屬性大小、類型;可以對其分割,但看不到它內部的細節

  • 聯系:Blob可以接受一個ArrayBuffer作為參數生成一個Blob對象,此行為就相當於對ArrayBuffer數據做一個封裝。

  • 應用上的區別:由於ArrayBufferBlob的特性,Blob作為一個整體文件,適合用於文件傳輸;而只有需要關注細節(比如要修改某一段數據時),此時使用ArrayBuffer比較好。

從以上我們的介紹以及聯系,我們可以得出如下的轉換函數

1
2
3
4
5
6
7
8
/**
** file轉blob
* @param {FileList} files fileList對象
* @param {String} type MIME類型
*/
function fileToBlob(files, type=''){
return new Blob(files, {type});
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* blob轉arrayBuffer,file轉arrayBuffer同理。
* file轉arrayBuffer也可通過FileReader,能控制更多交互細節,在此暫不介紹
**
* @param {Blob} blob blob對象
* @return {Promise} Promise對象
*/
function blobToArrayBuffer(blob) {
return new Promise((resolve, rejejct) => {
blob.arrayBuffer().then(buffer => {
resolve(buffer);
}).catch(err => {
rejejct(err);
});
});
}
 

弄清了他們之間的關系,在以后的工作學習中,才能剛好的去使用這些對象,讓其用在最適用的地方。而不是每次都一頭霧水,熟悉並陌生着。對於和他們相關的FileReader、Base64、FormData,后續會更新相關內容,將其進行聯系起來,更好的理解他們。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM