Html5——File躏嚎、FileReader、Blob憨募、Fromdata對象

原文:https://blog.csdn.net/mr_wuch/article/details/70141674

File


File 接口提供有關(guān)文件的信息紧索,并允許網(wǎng)頁中的JavaScript訪問其內(nèi)容。

File對象可以用來獲取某個文件的信息菜谣,還可以用來讀取這個文件的內(nèi)容珠漂。通常情況下尾膊,F(xiàn)ile對象是來自用戶在一個 <input> 元素上選擇文件后返回的FileList對象媳危,也可以是來自由拖放操作生成的 DataTransfer對象。

用戶在選擇一個或者多個文件后冈敛,可以通過File API訪問這些File對象待笑,這些對象被包含在一個FileList對象中。所有type為file的input都有一個files屬性抓谴,通過Element.files可以返回FileList對象暮蹂。

<body>
    <input type="file" id="fileInput" name="file" multiple="multiple" accept="image/*">

    <script>
        var fileInput = document.querySelector("#fileInput");
        fileInput.addEventListener("change", function (event) {
            var file = fileInput.files[0];
            console.log(fileInput.files)
        }, false)
    </script>
</body>
FileList對象

files有一個length屬性和item方法,可以通過files[index]或者files.item(index)獲取我們選擇的file對象癌压。每個File對象中包含了文件的一些詳細信息:

File對象

根據(jù)size屬性換算為我們習(xí)慣的文件大小單位:

function bytesToSize(bytes) {
    if (bytes === 0) return '0 B';  
    var k = 1024,
        sizes = ['B','KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    // Math.log() 返回數(shù)字的自然對數(shù) log(b)/log(a)=loga(b)) 換底公式 log以a為底b的對數(shù)
    // Math.floor(x) -- 向下取整仰泻,返回小于或等于x的值
    // Math.pow(x,y) -- 返回以x的y次冪,等同于x^y的數(shù)值表達式
    var i = Math.floor(Math.log(bytes) / Math.log(k));
    return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
}

FileReader


FileReader 對象允許Web應(yīng)用程序異步讀取存儲在用戶計算機上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容滩届,使用 FileBlob 對象指定要讀取的文件或數(shù)據(jù)

其中File對象可以是來自用戶在一個<input>元素上選擇文件后返回的FileList對象,也可以來自拖放操作生成的 DataTransfer對象,還可以是來自在一個HTMLCanvasElement上執(zhí)行mozGetAsFile()方法后返回結(jié)果

DataURI對象

先來看一個例子:

<body>
    <div id="dropbox" class="dropbox">
        <div class="area">拖動圖片到這里</div>
    </div>
    <div id="preview"></div>

    <script type="text/javascript">
        var dropbox = document.querySelector("#dropbox");
        var preview = document.querySelector("#preview");

        dropbox.addEventListener("dragenter", function (e) {
            e.stopPropagation();
            e.preventDefault();
        }, false);

        dropbox.addEventListener("dragover", function (e) {
            e.stopPropagation();
            e.preventDefault();
        }, false);

        dropbox.addEventListener("drop", function (e) {
            e.stopPropagation();
            e.preventDefault();

            var dt = e.dataTransfer;
            var files = dt.files;

            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                var imageType = new RegExp("^image\/");
                if (!imageType.test(file.type)) continue;

                // 填充選擇的圖片到展示區(qū)
                var img = document.createElement("img");
                img.classList.add("obj");
                img.file = file;
                preview.appendChild(img);

                // 讀取File對象中的內(nèi)容
                var reader = new FileReader();
                reader.onload = (function (aImg) {
                    return function (e) {
                        aImg.src = e.target.result;
                    };
                })(img);
                reader.readAsDataURL(file);
            }
        }, false);
    </script>
</body>
這里寫圖片描述

在上面的例子中集侯,預(yù)覽圖片的src使用了”data:image/png;base64,xxxxxxxxxxxxx”這種形式的字符串(base64),這種字符串叫做DataURI對象帜消,允許將一個小文件進行編碼后嵌入到另外一個文檔里棠枉,格式為:

data:[<MIME type>][;charset=<charset>][;base64],<encoded data>

這個字符串可以分為三部分,即聲明:參數(shù)+數(shù)據(jù)泡挺,逗號左邊的是各種參數(shù)辈讶,右邊的是數(shù)據(jù)。

我們可以通過FileReader 的readAsDataURL方法獲得文件的DataURI

readAsDataURL()

開始讀取指定的Blob對象或File對象中的內(nèi)容娄猫。當讀取操作完成時贱除,readyState屬性的值會成為DONE咳促,如果設(shè)置了onloadend事件處理程序,則調(diào)用之勘伺。同時,result屬性中將包含一個data:URL格式的字符串以表示所讀取文件的內(nèi)容褂删。

var reader = new FileReader();
reader.onload = function() {
    console.log(this.result);
}
reader.readAsDataURL(file);

URL對象

除了可以使用base64字符串作為內(nèi)容的DataURI將一個文件嵌入到另外一個文檔里飞醉,還可以使用URL對象。URL對象用于生成指向File對象或Blob對象的URL

靜態(tài)方法:

  • URL.createObjectURL()
    該方法會創(chuàng)建一個 DOMString屯阀,其中包含一個表示參數(shù)中給出的對象的URL缅帘。這個 URL 的生命周期和創(chuàng)建它的窗口中的 document 綁定。這個新的URL 對象表示指定的 File 對象或 Blob 對象难衰。

    objectURL = URL.createObjectURL(blob);
    

    blob 是用來創(chuàng)建 URL 的 File 對象或者 Blob 對象?

  • URL.revokeObjectURL()
    該方法用來釋放一個之前通過調(diào)用 URL.createObjectURL() 創(chuàng)建的已經(jīng)存在的 URL 對象钦无。當你結(jié)束使用某個 URL 對象時,應(yīng)該通過調(diào)用這個方法來讓瀏覽器知道不再需要保持這個文件的引用了盖袭。

    window.URL.revokeObjectURL(objectURL);
    

    objectURL 是一個 DOMString失暂,表示通過調(diào)用 URL.createObjectURL() 方法產(chǎn)生的 URL 對象

同樣以拖拽上傳圖片預(yù)覽為例子:

<body>
    <div id="dropbox" class="dropbox">
        <div class="area">拖動圖片到這里</div>
    </div>
    <div id="preview"></div>

    <script type="text/javascript">
        var dropbox = document.querySelector("#dropbox");
        var preview = document.querySelector("#preview");

        dropbox.addEventListener("dragenter", function (e) {
            e.stopPropagation();
            e.preventDefault();
        }, false);

        dropbox.addEventListener("dragover", function (e) {
            e.stopPropagation();
            e.preventDefault();
        }, false);

        dropbox.addEventListener("drop", function (e) {
            e.stopPropagation();
            e.preventDefault();
            console.log(e)
            var dt = e.dataTransfer;
            var files = dt.files;
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                var imageType = new RegExp("^image\/");
                if (!imageType.test(file.type)) {
                    console.log(1)
                    continue;
                }
                // 填充選擇的圖片到展示區(qū)
                var img = document.createElement("img");
                img.classList.add("obj");
                img.file = file;
                img.src = window.URL.createObjectURL(file);
                preview.appendChild(img);
            }
        }, false);
    </script>
</body>
這里寫圖片描述

Blob 二進制大對象


什么是Blob對象?

實際上上文的File對象只是 Blob 對象的一個更具體的版本鳄虱,Blob對象 存儲著大量的二進制數(shù)據(jù)弟塞,并且 Blob 的 size 和 type 屬性,都會被 File 對象所繼承拙已。同樣FileReader對象也可以從Blob對象中讀取數(shù)據(jù)决记。

一個 Blob對象表示一個不可變的, 原始數(shù)據(jù)的類似文件對象。Blob表示的數(shù)據(jù)不一定是一個JavaScript原生格式倍踪。 File 接口基于Blob系宫,繼承 blob功能并將其擴展為支持用戶系統(tǒng)上的文件酱床。

使用 Blob() 構(gòu)造函數(shù)可以構(gòu)造一個Blob從其他非blob對象和數(shù)據(jù)种蝶。要創(chuàng)建一個包含另一個blob的數(shù)據(jù)子集的blob,使用 slice() 方法贱鄙。

Blob 構(gòu)造函數(shù)生成blob對象

Blob構(gòu)造函數(shù)癞志,接受兩個參數(shù)往枷。第一個參數(shù)是一個包含實際數(shù)據(jù)的數(shù)組,第二個參數(shù)是數(shù)據(jù)的類型凄杯,這兩個參數(shù)都不是必需的错洁。數(shù)組元素可以是任意多個的ArrayBuffer,ArrayBufferView (typed array)戒突, Blob屯碴,或者 DOMString對象。例如:

var arr = ['<h1>hello world</h1>'];
var blob = new Blob(arr, { "type" : "text/xml" }); // the blob
console.log(blob);

slice方法生成blob對象

Blob對象的slice方法膊存,將二進制數(shù)據(jù)按照字節(jié)分塊导而,返回一個新的Blob對象

var newBlob = oldBlob.slice(startingByte, endindByte);

返回一個新的 Blob 對象忱叭,包含了源 Blob 對象中指定范圍內(nèi)的數(shù)據(jù)。

使用XMLHttpRequest對象今艺,將大文件分割上傳:

function upload(blobOrFile) {
  var xhr = new XMLHttpRequest();
  xhr.open('POST', '/server', true);
  xhr.onload = function(e) { ... };
  xhr.send(blobOrFile);
}

document.querySelector('input[type="file"]').addEventListener('change', function(e) {
  var blob = this.files[0];

  const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
  const SIZE = blob.size;

  var start = 0;
  var end = BYTES_PER_CHUNK;

  while(start < SIZE) {
    upload(blob.slice(start, end));
    start = end;
    end = start + BYTES_PER_CHUNK;
  }
}, false);

DataURI(base64)對象轉(zhuǎn)blob對象(二進制)

/**
 * dataURL to blob, ref to https://gist.github.com/fupslot/5015897
 * @param dataURI
 * @returns {Blob}
 */
function dataURItoBlob(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], {type: mimeString});
}
// atob() 將base64解碼
// btoa() 將字符串轉(zhuǎn)碼為base64
var str = 'javascript';
window.btoa(str)
//轉(zhuǎn)碼結(jié)果 "amF2YXNjcmlwdA=="
window.atob("amF2YXNjcmlwdA==")
//解碼結(jié)果 "javascript"

FormData

用FormData對象,我們可以通過JavaScript用一些鍵值對來模擬一系列表單控件,我們還可以使用XMLHttpRequest的send()方法來異步的提交這個”表單”.比起普通的ajax,使用FormData的最大優(yōu)點就是我們可以異步上傳一個二進制文件

FormData對象的作用類似于jQuery里面的 serialize() 方法韵丑,serialize() 作用就是表單序列化,也就是以查詢字符串形式獲得類表單post/get的數(shù)據(jù)給Ajax請求虚缎,例如:userid=123&username=zxx撵彻。

使用

new FormData (form? : HTMLFormElement)

form 參數(shù)可選,是一個HTML表單元素实牡,可以包含任何形式的表單控件,包括文件輸入框陌僵。

方法

append() 給當前FormData對象添加一個鍵/值對

void append(DOMString 鍵, Blob 值, [可選] DOMString 文件名);
void append(DOMString 鍵, DOMString 值);
  • name 字段名稱
  • value 字段值,可以是Blob value创坞,或者一個字符串碗短,如果全都不是,則該值會被自動轉(zhuǎn)換成字符串

使用FromData對象上傳文件

  1. 通過HTML表單創(chuàng)建FormData對象提交上傳(base64)
<form id="uploadForm" enctype="multipart/form-data">
    <input id="file" type="file" name="file"/>
    <button id="upload" type="button">upload</button>
</form>
$.ajax({
    url: '/upload',
    type: 'POST',
    cache: false,
    data: new FormData($('#uploadForm')[0]),
    processData: false,
    contentType: false
}).done(function(res) {
}).fail(function(res) {});
  1. 構(gòu)造 FormData 填充二進制文件數(shù)據(jù)题涨,通過 ajax 的方式進行提交:
var fd = new FormData(); // 構(gòu)造FromData對象
var blob = dataURItoBlob(dataURI); // 將base64轉(zhuǎn)為二進制blob對象
fd.append('file', blob);
$.ajax({
    type: 'POST',
    url: '/upload',
    data: fd,
    processData: false, // 不會將 data 參數(shù)序列化字符串,必須false
    contentType: false, // 根據(jù)表單 input 提交的數(shù)據(jù)使用其默認的 contentType偎谁,必須false
    xhr: function() {
        var xhr = new window.XMLHttpRequest();
        xhr.upload.addEventListener("progress", function(evt) {
            if (evt.lengthComputable) {
                var percentComplete = evt.loaded / evt.total;
                console.log('進度', percentComplete);
            }
        }, false);

        return xhr;
    }
}).success(function (res) {
    // 拿到提交的結(jié)果
}).error(function (err) {
    console.error(err);
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纲堵,隨后出現(xiàn)的幾起案子搭盾,更是在濱河造成了極大的恐慌,老刑警劉巖婉支,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸯隅,死亡現(xiàn)場離奇詭異,居然都是意外死亡向挖,警方通過查閱死者的電腦和手機蝌以,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來何之,“玉大人跟畅,你說我怎么就攤上這事∪芡疲” “怎么了徊件?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蒜危。 經(jīng)常有香客問我虱痕,道長,這世上最難降的妖魔是什么辐赞? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任部翘,我火速辦了婚禮,結(jié)果婚禮上响委,老公的妹妹穿的比我還像新娘新思。我一直安慰自己窖梁,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布夹囚。 她就那樣靜靜地躺著纵刘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荸哟。 梳的紋絲不亂的頭發(fā)上彰导,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音敲茄,去河邊找鬼。 笑死山析,一個胖子當著我的面吹牛堰燎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笋轨,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秆剪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了爵政?” 一聲冷哼從身側(cè)響起仅讽,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钾挟,沒想到半個月后洁灵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡掺出,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年徽千,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汤锨。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡双抽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闲礼,到底是詐尸還是另有隱情牍汹,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布柬泽,位于F島的核電站慎菲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锨并。R本人自食惡果不足惜钧嘶,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琳疏。 院中可真熱鬧有决,春花似錦闸拿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至台汇,卻和暖如春苛骨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苟呐。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工痒芝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牵素。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓严衬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親笆呆。 傳聞我的和親對象是個殘疾皇子请琳,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353