前面的話
Blob是計算機界通用術語之一,全稱寫作:BLOB(binary large object),表示二進制大對象。MySql/Oracle數據庫中,就有一種Blob類型,專門存放二進制數據。在javascript中,Blob通常表示二進制數據,不過它們不一定非得是大量數據,Blob也可以表示一個小型文本文件的內容。本文將詳細介紹Blob
構造函數
Blob(array[, options])
Blob()構造函數返回一個新的Blob對象,blob的內容由參數數組中給出的值的串聯組成
[注意]IE9-瀏覽器不支持
參數array是一個由ArrayBuffer、ArrayBufferView、Blob、DOMString等對象構成的Array,或者其他類似對象的混合體,它將會被放進Blob
參數options是一個可選項,它可能會指定如下兩種屬性:
1、類型,默認值為"",它代表了將會被放入到blob中的數組內容的MIME類型
2、結束符,默認值為"transparent",它代表包含行結束符\n的字符串如何被輸出。它是以下兩個值中的一個:"native",代表行結束符會被更改為適合宿主操作系統文件系統的慣例,或者"transparent",代表會保持blob中保存的結束符不變
var aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); console.log(oMyBlob);//Blob {size: 32, type: "text/html"}
屬性和方法
Blob是不透明的,能對它們進行直接操作的就只有獲取它們的大小(以字節為單位)、MIME類型以及將它們分割成更小的Blob
Blob.size(只讀):返回Blob對象中所包含數據的大小(字節)
Blob.type(只讀):一個字符串,表明該Blob對象所包含數據的MIME類型。如果類型未知,則該值為空字符串
var myBlob = new Blob([1,2,3],{type:'text/plain'}); console.log(myBlob);//Blob {size: 3, type: "text/plain"} console.log(myBlob.size);//3 console.log(myBlob.type);//'text/plain'
Blob.slice([start[, end[, contentType]]])
slice()方法返回一個新的Blob對象,包含了源Blob對象中指定范圍內的數據
var subblob = blob.slice(0,1024, "text/plain");//Blob中前1KB視為文本 var last = blob.slice(blob.size-1024, 1024);//Blob中最后1KB視為無類型
Web瀏覽器可以將Blob存儲到內存中或者磁盤上,Blob可以表示非常大的數據塊(比如視頻文件),如果事先不用slice()方法將它們分割成為小數據塊的話,無法存儲在主內存中。正是因為Blob可以表示非常大的數據塊,並且它可能需要磁盤的訪問權限,所以使用它們的API是異步的(在Worker線程中有提供相應的同步版本)
文件作為Blob
在使用Blob之前,首先必須要獲取Blob。其中一種方式就是把文件作為Blob
<input type="file">元素最初是用於在HTML表單中實現文件上傳的。瀏覽器總是很小心地實現該元素,目的是為了只允許上傳用戶顯式選擇的文件。腳本是無法將該元素的value屬性設置成一個文件名的,這樣它們就無法實現將用戶電腦上任意的文件進行上傳。現在,瀏覽器已經對該元素進行了擴展,允許客戶端可以訪問用戶選擇的文件了
[注意]允許客戶端腳本讀取選擇的文件內容不會引發安全問題,它和允許這些文件上傳到服務器的安全級別是一樣的
在支持本地文件訪問的瀏覽器中,<input type="file">元素上的files屬性則是一個FileList對象。該對象是一個類數組對象,其元素要么是0,要么是用戶選擇的多個File對象。一個File對象就是一個Blob,除此之外,還多了name和lastModifiedDate屬性
<script> //輸出選中的文件列表相關的信息 function fileinfo(files) { for(var i = 0; i < files.length; i++) {//files是一個類數組對象 var f = files[i]; //a.txt 86 text/plain Mon Sep 19 2016 11:07:43 GMT+0800 (中國標准時間) console.log(f.name, //只是名字:沒有路徑 f.size, f.type, //size和type是Blob的屬性 f.lastModifiedDate); //修改時間 } } </script> <input type="file" onchange="fileinfo(this.files)"/>
下載Blob
在實際Web應用中,Blob更多是圖片二進制形式的上傳與下載,雖然其可以實現幾乎任意文件的二進制傳輸
第二種獲取Blob的形式是通過XHR下載Blob
var xhr = new XMLHttpRequest(); //創建一個新的XHR對象 xhr.open('GET','p5.gif'); //指定要獲取內容的URL xhr.responseType = 'blob'; //以Blob的形式 xhr.onload = function(){ //onload 比onreadystatechange更容易 //Blob {size: 944, type: "image/gif"} console.log(xhr.response); //response返回的就是Blob對象 } xhr.send(null); //發送請求
Blob URL
前面介紹了如何獲取或者創建Blob。下面來介紹如何對獲取或者創建的Blob進行操作。其中最簡單的就是可以創建一個URL來指向該Blob。隨后,可以以一般的URL形式在任何地方使用該URL:在D0M中、在樣式表中、甚至可以作為XMLHttpRequest的目標
【createObjectURL()】
使用createObjectURL()函數可以創建一個Blob URL。URL.createObjectURL()靜態方法會創建一個DOMString,它的URL表示參數中的對象。這個URL的生命周期和創建它的窗口中的document綁定。這個新的URL對象表示着指定的File對象或者Blob對象
objectURL = URL.createObjectURL(blob);
傳遞一個Blob給createObjectURL()方法會返回一個URL(以普通字符串形式)。該URL以blob://開始,緊跟着是一小串文本字符串,該字符串用不透明的唯一標識符來標識Blob
var xhr = new XMLHttpRequest();
xhr.open('GET','test/p5.gif');
xhr.responseType = 'blob';
xhr.onload = function(){
//blob:http://127.0.0.1/539ae798-70db-44db-b216-fc932b358285
console.log(URL.createObjectURL(xhr.response));
}
xhr.send(null);
[注意]blob://URL和data://URL是不同的,data://URL會對內容進行編碼。blob://URL只是對瀏覽器存儲在內存中或者磁盤上的Blob的一個簡單引用
【file URL】
blob://URL和file://URL也是不同的,file://URL直接指向本地文件系統中的一個文件,僅暴露了文件的路徑、瀏覽目錄的許可等,除此之外任何內容都會帶來安全問題的
Blob URL和創建它們的腳本擁有同樣的源。這使得它們比file://URL更加靈活,由於file://URL是非同源的,因此要在Web應用中使用它們相對比較麻煩。Blob://URL只有在同源的文檔中才是有效的。比如,如果將一個Blob URL通過postMessage()傳遞給一個非同源窗口,則該URL對於該窗口來說是沒有任何意義的
Blob URL並不是永久有效的。一旦用戶關閉了或者離開了包含創建Blob URL腳本的文 檔,該Blob URL就失效了。比如,將Blob URL保存到本地存儲器中,然后當用戶開始一個新的Web應用會話的時再使用它,是不可能的
【URL.revokeObjectURL()】
URL.revokeObjectURL()靜態方法用來釋放一個之前通過調用URL.createObjectURL() 創建的已經存在的URL對象。當結束使用某個URL對象時,應該通過調用這個方法來讓瀏覽器知道不再需要保持這個文件的引用了
window.URL.revokeObjectURL(objectURL);
參數objectURL是一個DOMString,表示通過調用URL.createObjectURL()方法產生的URL對象
之所以提供這樣的方式,是因為這和內存管理問題有關。一旦使用之后,Blob就不再需要了,應當回收它。但是,如果Web瀏覽器正維護創建的Blob和Blob URL之間的映射關系,那么即使該Blob已經不用了,也不會被回收。javascript解釋器無法跟蹤字符串的使用情況,如果URL仍然是有效的,那么它只能認為該URL可能還在用。這就意味着,在手動撤銷該URL之前,是不會將其回收的