前端H5中JS用FileReader對象讀取blob對象二進制數據,文件傳輸

HTML5中的Blob對象只是二進制數據的容器,自己並不能操做二進制,故本篇將對其操做對象FileReader進行介紹。前端

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]))
}

readAsDataURL

查看圖片輸出結果:
異步

查看txt輸出結果:
ide

很明顯,readAsDataURL會將文件內容進行base64編碼後輸出,這個很好區分。函數

readAsText

此方法能夠經過不一樣的編碼方式讀取字符,咱們使用utf-8讀取
查看圖片輸出結果:

查看txt輸出結果:

readAsText讀取文件的單位是字符,故對於文本文件,只要按規定的編碼方式讀取便可;
而對於媒體文件(圖片、音頻、視頻),其內部組成並非按字符排列,故採用readAsText讀取,會產生亂碼,同時也不是最理想的讀取文件的方式

readAsBinaryString

查看圖片輸出結果:

查看txt輸出結果:

與readAsText不一樣的是,readAsBinaryString函數會按字節讀取文件內容。
然而諸如0101的二進制數據只能被機器識別,若想對外可見,仍是須要進行一次編碼,而readAsBinaryString的結果就是讀取二進制並編碼後的內容。
儘管readAsBinaryString方法能夠按字節讀取文件,但因爲讀取後的內容被編碼爲字符,大小會受到影響,故不適合直接傳輸,也不推薦使用。
如:測試的圖片文件原大小爲6764 字節,而經過readAsBinaryString讀取後,內容被擴充到10092個字節

readAsArrayBuffer

查看圖片輸出結果:

查看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 有何區別

相關文章
相關標籤/搜索