HTML5中的Blob對象只是二進制數據的容器,自己並不能操做二進制,故本篇將對其操做對象FileReader進行介紹。前端
FileReader主要用於將文件內容讀入內存,經過一系列異步接口,能夠在主線程中訪問本地文件。web
使用FileReader對象,web應用程序能夠異步的讀取存儲在用戶計算機上的文件(或者原始數據緩衝)內容,可使用File對象或者Blob對象來指定所要處理的文件或數據。後端
var reader = new FileReader();
方法定義 | 描述 |
---|---|
abort():void | 終止文件讀取操做 |
readAsArrayBuffer(file):void | 異步按字節讀取文件內容,結果用ArrayBuffer對象表示 |
readAsBinaryString(file):void | 異步按字節讀取文件內容,結果爲文件的二進制串 |
readAsDataURL(file):void | 異步讀取文件內容,結果用data:url的字符串形式表示 |
readAsText(file,encoding):void | 異步按字符讀取文件內容,結果用字符串形式表示 |
事件名稱 | 描述 |
---|---|
onabort | 當讀取操做被停止時調用 |
onerror | 當讀取操做發生錯誤時調用 |
onload | 當讀取操做成功完成時調用 |
onloadend | 當讀取操做完成時調用,不論是成功仍是失敗 |
onloadstart | 當讀取操做將要開始以前調用 |
onprogress | 在讀取數據過程當中週期性調用 |
FileReader經過異步的方式讀取文件內容,結果均是經過事件回調獲取,下面是一個讀取本地txt文件內容的例子:數組
var input = document.getElementById("file"); //input file input.onchange = function(){ var file = this.files[0]; if(!!file){ //讀取本地文件,以gbk編碼方式輸出 var reader = new FileReader(); reader.readAsText(file,"gbk"); reader.onload = function(){ //讀取完畢後輸出結果 console.log(this.result); } } }
此外咱們還能夠經過註冊onprogress、onerror等事件,記錄文件讀取進度或異常行爲等等。服務器
FileReader提供了四種不一樣的讀取文件的方式,如:readAsArrayBuffer會將文件內容讀取爲ArrayBuffer對象,readAsBinaryString則將文件讀取爲二進制串,下面對這四種方式進行簡單區分。
首先準備一張圖片(6764 字節)和一個txt文本(51字節)做爲測試文件:
網絡
接着編寫測試代碼:app
var reader = new FileReader(); // 經過四種方式讀取文件 //reader.readAsXXX(file); reader.onload = function(){ //查看文件輸出內容 console.log(this.result); //查看文件內容字節大小 console.log(new Blob([this.result])) }
查看圖片輸出結果:
異步
查看txt輸出結果:
ide
很明顯,readAsDataURL會將文件內容進行base64編碼後輸出,這個很好區分。函數
此方法能夠經過不一樣的編碼方式讀取字符,咱們使用utf-8
讀取
查看圖片輸出結果:
查看txt輸出結果:
readAsText讀取文件的單位是字符,故對於文本文件,只要按規定的編碼方式讀取便可;
而對於媒體文件(圖片、音頻、視頻),其內部組成並非按字符排列,故採用readAsText讀取,會產生亂碼,同時也不是最理想的讀取文件的方式
查看圖片輸出結果:
查看txt輸出結果:
與readAsText不一樣的是,readAsBinaryString函數會按字節讀取文件內容。
然而諸如0101的二進制數據只能被機器識別,若想對外可見,仍是須要進行一次編碼,而readAsBinaryString的結果就是讀取二進制並編碼後的內容。
儘管readAsBinaryString方法能夠按字節讀取文件,但因爲讀取後的內容被編碼爲字符,大小會受到影響,故不適合直接傳輸,也不推薦使用。
如:測試的圖片文件原大小爲6764 字節,而經過readAsBinaryString讀取後,內容被擴充到10092個字節
查看圖片輸出結果:
查看txt輸出結果:
與readAsBinaryString相似,readAsArrayBuffer方法會按字節讀取文件內容,並轉換爲ArrayBuffer對象。
咱們能夠關注下文件讀取後大小,與原文件大小一致。
這也就是readAsArrayBuffer與readAsBinaryString方法的區別,readAsArrayBuffer讀取文件後,會在內存中建立一個ArrayBuffer對象(二進制緩衝區),將二進制數據存放在其中。經過此方式,咱們能夠直接在網絡中傳輸二進制內容。
好了說這麼多,那ArrayBuffer究竟是個毛?
關於ArrayBuffer對象牽涉的知識點比較多,徹底能夠單開一篇細說,在此只要簡單理解爲存放了一段二進制數據的內存空間便可。
而自己ArrayBuffer中的內容對外是不可見的,若要查看其中的內容,就要引入另外一個概念:類型化數組
咱們能夠嘗試查看下剛剛經過readAsArrayBuffer方法讀取的圖片文件內容:
能夠看到,整個圖片文件的6764個字節,被分別存儲在長度爲6764的數組中,而數組中每個元素的值,爲當前字節的十進制數值。
關於ArrayBuffer和類型化數組的概念在此不作深刻解釋,以後會再寫一篇單獨討論。
說了這麼多,最後仍是要落實到FileReader能解決什麼問題,下面經過幾個例子說明:
咱們知道,img的src屬性或background的url屬性,能夠經過被賦值爲圖片網絡地址或base64的方式顯示圖片。
在文件上傳中,咱們通常會先將本地文件上傳到服務器,上傳成功後,由後臺返回圖片的網絡地址再在前端顯示。
經過FileReader的readAsDataURL方法,咱們能夠不通過後臺,直接將本地圖片顯示在頁面上。這樣作能夠減小先後端頻繁的交互過程,減小服務器端無用的圖片資源,代碼以下:
var input = document.getElementById("file"); // input file input.onchange = function(){ var file = this.files[0]; if(!!file){ var reader = new FileReader(); // 圖片文件轉換爲base64 reader.readAsDataURL(file); reader.onload = function(){ // 顯示圖片 document.getElementById("file_img").src = this.result; } } }
運行效果以下:
對於圖片上傳,咱們也能夠先將圖片轉換爲base64進行傳輸,此時因爲傳輸的圖片內容就是一段字符串,故上傳接口能夠當作普通post接口處理,當圖片傳輸到後臺後,能夠在轉換爲文件實體存儲。
固然,考慮到base64轉換效率及其自己的大小,本方法仍是適合於上傳內容簡單或所佔內存較小的文件。
HTML5體系的創建引入了一大堆新的東西,基於XHR2,咱們能夠直接上傳或下載二進制內容,無需像以往同樣經過form標籤由後端拉取二進制內容。
簡單整理下上傳邏輯:
一、經過input[type="file"]標籤獲取本地文件File對象
二、經過FileReader的readAsArrayBuffer方法將File對象轉換爲ArrayBuffer
三、建立xhr對象,配置請求信息
四、經過xhr.sendAsBinary直接將文件的ArrayBuffer內容裝填至post body後發送
代碼實現以下:
var input = document.getElementById("file"); // input file input.onchange = function(){ var file = this.files[0]; if(!!file){ var reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = function(){ var binary = this.result; upload(binary); } } } //文件上傳 function upload(binary){ var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xxxx/opload"); xhr.overrideMimeType("application/octet-stream"); //直接發送二進制數據 if(xhr.sendAsBinary){ xhr.sendAsBinary(binary); }else{ xhr.send(binary); } // 監聽變化 xhr.onreadystatechange = function(e){ if(xhr.readyState===4){ if(xhr.status===200){ // 響應成功 } } } }
本篇主要介紹了FileReader對象的屬性及應用場景,有了FileReader,咱們能夠將本地文件讀取到內存中。文中咱們提到了ArrayBuffer和類型化數組的概念,這使得咱們能夠在內存中進一步操做二進制數據,關於這部份內容,會在以後的博客中進行概括。
[1] MDN_FileReader
[2] Unicode 和 UTF-8 有何區別