前言
在前端中處理檔案時會經常遇到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
|
const fileList = document.getElementById('file').files;
|
在這幾個當中,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
|
/**
|
array 是一個由
ArrayBuffer
,ArrayBufferView
,Blob
,DOMString
等物件構成的Array
,或者其他類似物件的混合體,它將會被放進Blob
。DOMStrings
會被編碼為UTF-8。options 是一個可選的
BlobPropertyBag
字典,它可能會指定如下兩個屬性:
type
,預設值為""
,它代表了將會被放入到blob中的陣列內容的MIME型別。endings
,預設值為"transparent"
,用於指定包含行結束符\n
的字串如何被寫入。 它是以下兩個值中的一個:"native"
,代表行結束符會被更改為適合宿主作業系統檔案系統的換行符,或者"transparent"
,代表會保持blob中儲存的結束符不變
使用示例:
1
|
const data1 = "a";
|
以上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
(資料檢視)物件來操作它,它們會將緩衝區中的資料表示為特定的格式,並通過這些格式來讀寫緩衝區的內容。TypedArray
給ArrayBuffer
提供了一個“View
”,對它們進行下標讀寫。也可以使用DataView來讀寫ArrayBuffer
,DataView
能更自由的選擇位元組序,不用考慮不同平臺的位元組序問題。
MDN將
ArrayBuffer
物件定義為用來表示通用的、固定長度的原始二進位制資料緩衝區。它是一個位元組陣列,通常在其他語言中稱為“byte array”。
用法示例
由於ArrayBuffer
不能直接進行操作,故需要藉助TypedArray
或者DataView
來進行讀寫。
1
|
// 生成一個可以16個位元組的連續記憶體,每個位元組的預設值是0
|
結語
區別/聯絡
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
7const 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
-
相同點:
Blob
和ArrayBuffer
都是二進位制的容器。 -
ArrayBuffer:
ArrayBuffer
更底層,是一段純粹的記憶體上的二進位制資料,我們可以對其任何一個位元組進行單獨的修改,也可以根據我們的需要以我們指定的形式讀取指定範圍的資料。 -
Blob:
Blob
就是將二進位制資料做了一個封裝,我們拿到的就是一個整體,可以看到它的整體屬性大小、型別;可以對其分割,但看不到它內部的細節 -
聯絡:
Blob
可以接受一個ArrayBuffer
作為引數生成一個Blob
物件,此行為就相當於對ArrayBuffer
資料做一個封裝。 -
應用上的區別:由於
ArrayBuffer
和Blob
的特性,Blob
作為一個整體檔案,適合用於檔案傳輸;而只有需要關注細節(比如要修改某一段資料時),此時使用ArrayBuffer
比較好。
從以上我們的介紹以及聯絡,我們可以得出如下的轉換函式
1
|
/**
|
1
|
/**
|
弄清了他們之間的關係,在以後的工作學習中,才能剛好的去使用這些物件,讓其用在最適用的地方。而不是每次都一頭霧水,熟悉並陌生著。對於和他們相關的FileReader、Base64、FormData,後續會更新相關內容,將其進行聯絡起來,更好的理解他們。