利用Blob進(jìn)行文件上傳的完整步驟
Blob
Blob,Binary Large Object的縮寫(xiě),二進(jìn)制類(lèi)型的大對(duì)象,代表不可改變的原始數(shù)據(jù)
在計(jì)算機(jī)中,BLOB常常是數(shù)據(jù)庫(kù)中用來(lái)存儲(chǔ)二進(jìn)制文件的字段類(lèi)型。
Blob基本用法
Blob對(duì)象
Blob對(duì)象指的是字節(jié)序列,并且具有size屬性,是字節(jié)序列中的字節(jié)總數(shù),和一個(gè)type屬性,它是小寫(xiě)的ASCII編碼的字符串表示的媒體類(lèi)型字節(jié)序列。
size:以字節(jié)數(shù)返回字節(jié)序列的大小。獲取時(shí),符合要求的用戶(hù)代理必須返回一個(gè)FileReader或一個(gè)FileReaderSync對(duì)象可以讀取的總字節(jié)數(shù),如果Blob沒(méi)有要讀取的字節(jié),則返回0 。
type:小寫(xiě)的ASCII編碼字符串表示媒體類(lèi)型Blob。在獲取時(shí),用戶(hù)代理必須Blob以小寫(xiě)形式返回a類(lèi)型的ASCII編碼字符串,這樣當(dāng)它轉(zhuǎn)換為字節(jié)序列時(shí),它是可解析的MIME類(lèi)型,或者是空字符串(0字節(jié))如果是類(lèi)型無(wú)法確定。
構(gòu)造函數(shù)
創(chuàng)建blob對(duì)象本質(zhì)上和創(chuàng)建一個(gè)其他對(duì)象的方式是一樣的,都是使用Blob() 的構(gòu)造函數(shù)來(lái)進(jìn)行創(chuàng)建。 構(gòu)造函數(shù)接受兩個(gè)參數(shù):
第一個(gè)參數(shù)為一個(gè)數(shù)據(jù)序列,格式可以是ArrayBuffer, ArrayBufferView, Blob, DOMString
第二個(gè)參數(shù)是一個(gè)包含以下兩個(gè)屬性的對(duì)象
- type: MIME的類(lèi)型,
- endings: 決定第一個(gè)參數(shù)的數(shù)據(jù)格式。默認(rèn)值為"transparent",用于指定包含行結(jié)束符n的字符串如何被寫(xiě)入。 它是以下兩個(gè)值中的一個(gè): "native",表示行結(jié)束符會(huì)被更改為適合宿主操作系統(tǒng)文件系統(tǒng)的換行符; "transparent",表示會(huì)保持blob中保存的結(jié)束符不變。
var data1 = "a"; var blob1 = new Blob([data1]); console.log(blob1); //輸出:Blob {size: 1, type: ""} var debug = {hello: "world"}; var blob = new Blob([JSON.stringify(debug, null, 2)],{type : 'application/json'}); console.log(blob) // 輸出 Blob(22) {size: 22, type: "application/json"} // 創(chuàng)建一個(gè)8字節(jié)的ArrayBuffer,在其上創(chuàng)建一個(gè)每個(gè)數(shù)組元素為2字節(jié)的“視圖” var abf = new ArrayBuffer(8) var abv = new Int16Array(abf) var bolb_ArrayBuffer = new Blob(abv, {type : 'text/plain'}) console.log(bolb_ArrayBuffer) //輸出 Blob(4) {size: 4, type: "text/plain"}
slice方法
Blob對(duì)象有一個(gè)slice方法,返回一個(gè)新的 Blob對(duì)象,包含了源 Blob對(duì)象中指定范圍內(nèi)的數(shù)據(jù)。
slice(start, end, contentType)
start: 可選,代表 Blob 里的下標(biāo),表示第一個(gè)會(huì)被會(huì)被拷貝進(jìn)新的 Blob 的字節(jié)的起始位置。如果傳入的是一個(gè)負(fù)數(shù),那么這個(gè)偏移量將會(huì)從數(shù)據(jù)的末尾從后到前開(kāi)始計(jì)算。
end: 可選,代表的是 Blob 的一個(gè)下標(biāo),這個(gè)下標(biāo)-1的對(duì)應(yīng)的字節(jié)將會(huì)是被拷貝進(jìn)新的Blob 的最后一個(gè)字節(jié)。如果你傳入了一個(gè)負(fù)數(shù),那么這個(gè)偏移量將會(huì)從數(shù)據(jù)的末尾從后到前開(kāi)始計(jì)算。
contentType: 可選,給新的 Blob 賦予一個(gè)新的文檔類(lèi)型。這將會(huì)把它的 type 屬性設(shè)為被傳入的值。它的默認(rèn)值是一個(gè)空的字符串。
var data = "abcdef"; var blob1 = new Blob([data]); var blob2 = blob1.slice(0,3); console.log(blob1); //輸出:Blob {size: 6, type: ""} console.log(blob2); //輸出:Blob {size: 3, type: ""}
slice用于文件分片上傳
- 分片與并發(fā)結(jié)合,將一個(gè)大文件分割成多塊,并發(fā)上傳,極大地提高大文件的上傳速度。
- 當(dāng)網(wǎng)絡(luò)問(wèn)題導(dǎo)致傳輸錯(cuò)誤時(shí),只需要重傳出錯(cuò)分片,而不是整個(gè)文件。另外分片傳輸能夠更加實(shí)時(shí)的跟蹤上傳進(jìn)度。
分片上傳邏輯如下:
獲取要上傳文件的File對(duì)象,根據(jù)chunk(每片大?。?duì)文件進(jìn)行分片
通過(guò)post方法輪循上傳每片文件,其中url中拼接querystring用于描述當(dāng)前上傳的文件信息;post body中存放本次要上傳的二進(jìn)制數(shù)據(jù)片段
接口每次返回offset,用于執(zhí)行下次上傳
initUpload(); //初始化上傳 function initUpload() { var chunk = 100 * 1024; //每片大小 var input = document.getElementById("file"); //input file input.onchange = function (e) { var file = this.files[0]; var query = {}; var chunks = []; if (!!file) { var start = 0; //文件分片 for (var i = 0; i < Math.ceil(file.size / chunk); i++) { var end = start + chunk; chunks[i] = file.slice(start , end); start = end; } // 采用post方法上傳文件 // url query上拼接以下參數(shù),用于記錄上傳偏移 // post body中存放本次要上傳的二進(jìn)制數(shù)據(jù) query = { fileSize: file.size, dataSize: chunk, nextOffset: 0 } upload(chunks, query, successPerUpload); } } } // 執(zhí)行上傳 function upload(chunks, query, cb) { var queryStr = Object.getOwnPropertyNames(query).map(key => { return key + "=" + query[key]; }).join("&"); var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xxxx/opload?" + queryStr); xhr.overrideMimeType("application/octet-stream"); //獲取post body中二進(jìn)制數(shù)據(jù) var index = Math.floor(query.nextOffset / query.dataSize); getFileBinary(chunks[index], function (binary) { if (xhr.sendAsBinary) { xhr.sendAsBinary(binary); } else { xhr.send(binary); } }); xhr.onreadystatechange = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { var resp = JSON.parse(xhr.responseText); // 接口返回nextoffset // resp = { // isFinish:false, // offset:100*1024 // } if (typeof cb === "function") { cb.call(this, resp, chunks, query) } } } } } // 每片上傳成功后執(zhí)行 function successPerUpload(resp, chunks, query) { if (resp.isFinish === true) { alert("上傳成功"); } else { //未上傳完畢 query.offset = resp.offset; upload(chunks, query, successPerUpload); } } // 獲取文件二進(jìn)制數(shù)據(jù) function getFileBinary(file, cb) { var reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = function (e) { if (typeof cb === "function") { cb.call(this, this.result); } } }
Blob URL
blob協(xié)議的url使用時(shí)就像平時(shí)使用的url一樣,可以作為圖片請(qǐng)求地址,也可以作為文件請(qǐng)求地址。格式:
blob:http://XXX
- URL.createObjectURL(blob) 創(chuàng)建鏈接
- URL.revokeObjectURL(url)
下面是一個(gè)下載文件的示例,直接調(diào)用即可實(shí)現(xiàn)文件下載
// file是要下載的文件(blob對(duì)象) downloadHandler: function (file, fileName) { let link = document.createElement('a') link.href = window.URL.createObjectURL(file) link.download = fileName link.click() window.URL.revokeObjectURL(link.href) if (navigator.userAgent.indexOf('Firefox') > -1) { const a = document.createElement('a') a.addEventListener('click', function (e) { a.download = fileName a.href = URL.createObjectURL(file) }) let e = document.createEvent('MouseEvents') e.initEvent('click', false, false) a.dispatchEvent(e) } }
在從后臺(tái)獲取的數(shù)據(jù)接口中把返回類(lèi)型設(shè)置為blob
var x = new XMLHttpRequest(); x.responseType = 'blob'; // 返回一個(gè)blob對(duì)象
Blob URL和Data URL的區(qū)別
Blob URL
Data URL
- Blob URL的長(zhǎng)度一般比較短,但Data URL因?yàn)橹苯哟鎯?chǔ)圖片base64編碼后的數(shù)據(jù),往往很長(zhǎng),如上圖所示,瀏覽器在顯示Data URL時(shí)使用了省略號(hào)(…)。當(dāng)顯式大圖片時(shí),使用Blob URL能獲取更好的可能性。
- Blob URL可以方便的使用XMLHttpRequest獲取源數(shù)據(jù),比如設(shè)置XMLHttpRequest返回的數(shù)據(jù)類(lèi)型為blob
- Blob URL 只能在當(dāng)前應(yīng)用內(nèi)部使用,把Blob URL復(fù)制到瀏覽器的地址欄中,是無(wú)法獲取數(shù)據(jù)的。Data URL相比之下,就有很好的移植性,可以在任意瀏覽器中使用。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
在layui框架中select下拉框監(jiān)聽(tīng)更改事件的例子
今天小編就為大家分享一篇在layui框架中select下拉框監(jiān)聽(tīng)更改事件的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09淺談關(guān)于JS下大批量異步任務(wù)按順序執(zhí)行解決方案一點(diǎn)思考
這篇文章主要介紹了淺談關(guān)于JS下大批量異步任務(wù)按順序執(zhí)行解決方案一點(diǎn)思考,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01js判斷對(duì)象是否擁有某個(gè)key的兩種方法對(duì)比
JS中數(shù)組和對(duì)象是等同的,我們經(jīng)常遇到需要判斷一個(gè)key是否存在于對(duì)象中的情況,這篇文章主要給大家介紹了關(guān)于如何利用js判斷對(duì)象是否擁有某個(gè)key的兩種方法對(duì)比,需要的朋友可以參考下2023-12-12JS插件amCharts實(shí)現(xiàn)繪制柱形圖默認(rèn)顯示數(shù)值功能示例
這篇文章主要介紹了JS插件amCharts實(shí)現(xiàn)繪制柱形圖默認(rèn)顯示數(shù)值功能,結(jié)合實(shí)例形式分析了amCharts插件繪制柱形圖并顯示數(shù)值的相關(guān)操作技巧,需要的朋友可以參考下2019-11-11