二進(jìn)制數(shù)組
概念介紹
ArrayBuffer對象、TypedArray視圖和DataView視圖是 JavaScript 操作二進(jìn)制數(shù)據(jù)的一個(gè)接口。它們都是以數(shù)組的語法處理二進(jìn)制數(shù)據(jù),所以統(tǒng)稱為二進(jìn)制數(shù)組。
二進(jìn)制數(shù)組由三類對象組成。
(1)ArrayBuffer對象:代表內(nèi)存之中的一段二進(jìn)制數(shù)據(jù),可以通過“視圖”進(jìn)行操作?!耙晥D”部署了數(shù)組接口,這意味著,可以用數(shù)組的方法操作內(nèi)存。
(2)TypedArray視圖:共包括 9 種類型的視圖,比如Uint8Array(無符號(hào) 8 位整數(shù))數(shù)組視圖, Int16Array(16 位整數(shù))數(shù)組視圖, Float32Array(32 位浮點(diǎn)數(shù))數(shù)組視圖等等。
(3)DataView視圖:可以自定義復(fù)合格式的視圖,比如第一個(gè)字節(jié)是 Uint8(無符號(hào) 8 位整數(shù))、第二、三個(gè)字節(jié)是 Int16(16 位整數(shù))、第四個(gè)字節(jié)開始是 Float32(32 位浮點(diǎn)數(shù))等等,此外還可以自定義字節(jié)序。
-
簡單說,
ArrayBuffer對象代表原始的二進(jìn)制數(shù)據(jù),TypedArray視圖用來讀寫簡單類型的二進(jìn)制數(shù)據(jù),DataView視圖用來讀寫復(fù)雜類型的二進(jìn)制數(shù)據(jù)。
一、ArrayBuffer 對象
1. 概念介紹
ArrayBuffer對象代表儲(chǔ)存二進(jìn)制數(shù)據(jù)的一段內(nèi)存,它不能直接讀寫,只能通過視圖(TypedArray視圖和- -DataView視圖)來讀寫,視圖的作用是以指定格式解讀二進(jìn)制數(shù)據(jù)。通俗點(diǎn)的話就是arrbuffer是一個(gè)數(shù)組,只不過這個(gè)數(shù)組有點(diǎn)特殊,你只能看不能改,但是可以通過“視圖”進(jìn)行操作
2. 對象使用
ArrayBuffer也是一個(gè)構(gòu)造函數(shù),可以分配一段可以存放數(shù)據(jù)的連續(xù)內(nèi)存區(qū)域。
const buf = new ArrayBuffer(32);
上面代碼生成了一段 32 字節(jié)的內(nèi)存區(qū)域,每個(gè)字節(jié)的值默認(rèn)都是 0??梢钥吹?,ArrayBuffer構(gòu)造函數(shù)的參數(shù)是所需要的內(nèi)存大?。▎挝蛔止?jié))。
3. 實(shí)例屬性和方法
ArrayBuffer 對象有實(shí)例屬性 byteLength ,表示當(dāng)前實(shí)例占用的內(nèi)存字節(jié)長度(單位字節(jié)),一旦創(chuàng)建就不可變更(只讀) :
const buffer = new ArrayBuffer(32); 其中32表示二進(jìn)制數(shù)據(jù)占用的字節(jié)長度。
buffer.byteLength; // 32
ArrayBuffer 對象有實(shí)例方法 slice(),用來復(fù)制一部分內(nèi)存。
參數(shù)如下:
- start,整數(shù)類型,表示開始復(fù)制的位置。默認(rèn)從 0 開始。
- end,整數(shù)類型,表示結(jié)束復(fù)制的位置(不包括結(jié)束的位置)。如果省略,則表示復(fù)制到結(jié)束。
const buffer = new ArrayBuffer(32);
const buffer2 = buffer.slice(0);
二、DataView 視圖
1. 概念介紹
因?yàn)锳rrayBuffer只能讀,不能寫,所以為了可以編輯數(shù)據(jù),DataView 視圖和TypedArray出現(xiàn)了,DataView 視圖是一個(gè)可以從二進(jìn)制ArrayBuffer對象中讀寫多種數(shù)值類型的底層接口,使用它時(shí),不用考慮不同平臺(tái)的字節(jié)序問題,主要用來讀寫復(fù)雜類型的二進(jìn)制數(shù)據(jù)**。
2. 對象使用
const buf = new ArrayBuffer(32);
為了讀寫這段內(nèi)容,需要為它指定視圖。DataView視圖的創(chuàng)建,需要提供ArrayBuffer對象實(shí)例作為參數(shù)。
const buf = new ArrayBuffer(32);
const dataView = new DataView(buf);
dataView.getUint8(0) // 0
上面代碼對一段 32 字節(jié)的內(nèi)存,建立DataView視圖,然后以不帶符號(hào)的 8 位整數(shù)格式,從頭讀取 8 位二進(jìn)制數(shù)據(jù),結(jié)果得到 0,因?yàn)樵純?nèi)存的ArrayBuffer對象,默認(rèn)所有位都是 0。
三、TypedArray 視圖
1. 概念介紹
- 一個(gè)類型化數(shù)組(TypedArray)對象描述了一個(gè)底層的二進(jìn)制數(shù)據(jù)緩沖區(qū)(binary data buffer)的一個(gè)類數(shù)組視圖(view).
- 因?yàn)锳rrayBuffer只能讀不能寫,沒啥用。但是借助于TypedArray或者DataView就可以修改ArrayBuffer的內(nèi)容
- 你可以把TypedArray想象成一個(gè)基類,其中Uint8Array、Float32Array等都繼承于TypedArray(實(shí)際并不是繼承!)
2. 對象使用
TypedArray視圖,與DataView視圖的一個(gè)區(qū)別是,它不是一個(gè)構(gòu)造函數(shù),而是一組構(gòu)造函數(shù),代表不同的數(shù)據(jù)格式。
const buffer = new ArrayBuffer(12);
const x1 = new Int32Array(buffer);
x1[0] = 1;
const x2 = new Uint8Array(buffer);
x2[0] = 2;
x1[0] // 2
上面代碼對同一段內(nèi)存,分別建立兩種視圖:32 位帶符號(hào)整數(shù)(
Int32Array構(gòu)造函數(shù))和 8 位不帶符號(hào)整數(shù)(Uint8Array構(gòu)造函數(shù))。由于兩個(gè)視圖對應(yīng)的是同一段內(nèi)存,一個(gè)視圖修改底層內(nèi)存,會(huì)影響到另一個(gè)視圖。TypedArray視圖的構(gòu)造函數(shù),除了接受ArrayBuffer實(shí)例作為參數(shù),還可以接受普通數(shù)組作為參數(shù),直接分配內(nèi)存生成底層的ArrayBuffer實(shí)例,并同時(shí)完成對這段內(nèi)存的賦值。
const typedArray = new Uint8Array([0,1,2]);
typedArray.length // 3
typedArray[0] = 5;
typedArray // [5, 1, 2]
- 上面代碼使用
TypedArray視圖的Uint8Array構(gòu)造函數(shù),新建一個(gè)不帶符號(hào)的 8 位整數(shù)視圖。可以看到,Uint8Array直接使用普通數(shù)組作為參數(shù),對底層內(nèi)存的賦值同時(shí)完成。
3. 不同類型的一組構(gòu)造函數(shù)
- 解釋其中一種,其他的類似:
Uint8Array數(shù)組類型表示一個(gè)8位無符號(hào)整型數(shù)組,創(chuàng)建時(shí)內(nèi)容被初始化為0,里面的每個(gè)元素只占一個(gè)字節(jié)。創(chuàng)建完后,可以以對象的方式或使用數(shù)組下標(biāo)索引的方式引用數(shù)組中的元素。 -
TypedArray視圖支持的數(shù)據(jù)類型一共有 9 種(DataView視圖支持除Uint8C以外的其他 8 種)。
| 數(shù)據(jù)類型 | 字節(jié)長度 | 含義 | 對應(yīng)的 C 語言類型 |
|---|---|---|---|
| Int8 | 1 | 8 位帶符號(hào)整數(shù) | signed char |
| Uint8 | 1 | 8 位不帶符號(hào)整數(shù) | unsigned char |
| Uint8C | 1 | 8 位不帶符號(hào)整數(shù)(自動(dòng)過濾溢出) | unsigned char |
| Int16 | 2 | 16 位帶符號(hào)整數(shù) | short |
| Uint16 | 2 | 16 位不帶符號(hào)整數(shù) | unsigned short |
| Int32 | 4 | 32 位帶符號(hào)整數(shù) | int |
| Uint32 | 4 | 32 位不帶符號(hào)的整數(shù) | unsigned int |
| Float32 | 4 | 32 位浮點(diǎn)數(shù) | float |
| Float64 | 8 | 64 位浮點(diǎn)數(shù) | double |
4. 操作實(shí)例
-
實(shí)例主要實(shí)現(xiàn)了前端使用TypedArray編輯二進(jìn)制
因?yàn)锳rrayBuffer只讀不可寫,所以先把ArrayBuffer轉(zhuǎn)換為可以編輯的TypedArray, 然后修改typedArray的內(nèi)容, 接著再把二進(jìn)制的數(shù)據(jù)轉(zhuǎn)化為blob類型的數(shù)據(jù),再把blob對象轉(zhuǎn)化為一個(gè)url數(shù)據(jù), 接著就可以把blob文件下載下來:
var ab = new ArrayBuffer(32)
var iA = new Int8Array(ab)
iA[0] = 97;//把二進(jìn)制的數(shù)據(jù)的首位改為97 ,97為小寫字母a的ascll碼;
var blob = new Blob([iA], {type: "application/octet-binary"});//把二進(jìn)制的碼轉(zhuǎn)化為blob類型
var url = URL.createObjectURL(blob);
window.open(url)
Blob
一、概念介紹
Blob對象表示一個(gè)不可變、原始數(shù)據(jù)的類文件對象。它的數(shù)據(jù)可以按文本或二進(jìn)制的格式進(jìn)行讀取,也可以轉(zhuǎn)換成ReadableStream來用于數(shù)據(jù)操作。Blob 表示的不一定是JavaScript原生格式的數(shù)據(jù)。
File接口基于Blob,繼承了 blob 的功能并將其擴(kuò)展使其支持用戶系統(tǒng)上的文件。在實(shí)際Web應(yīng)用中,Blob更多是圖片二進(jìn)制形式的上傳與下載,雖然其可以實(shí)現(xiàn)幾乎任意文件的二進(jìn)制傳輸。
二、創(chuàng)建對象
- 創(chuàng)建Blob對象的方法有幾種,可以調(diào)用Blob構(gòu)造函數(shù),還可以使用一個(gè)已有Blob對象上的
slice()方法切出另一個(gè)Blob對象,還可以調(diào)用canvas對象上的toBlob方法。
三、屬性
Blob對象有兩個(gè)屬性,參見下表:
| 屬性名 | 類型 | 描述 |
|---|---|---|
| size | unsigned long long(表示可以很大的數(shù)值) | Blob對象中所包含數(shù)據(jù)的大小。字節(jié)為單位。 只讀。 |
| type | DOMString | 一個(gè)字符串,表明該Blob對象所包含數(shù)據(jù)的MIME類型。例如,上demo圖片MIME類似就是”image/jpeg“. 如果類型未知,則該值為空字符串。 只讀。
|
四、構(gòu)造函數(shù)
構(gòu)造函數(shù)
與FormData對象類似,Blob也有一個(gè)構(gòu)造函數(shù)用法。語法如下:
Blob Blob(
[可選] Array parts,
[可選] BlobPropertyBag properties
);
例如:
var myBlob= new Blob(arrayBuffer);
其中,兩個(gè)參數(shù)的含義是:
-
parts一個(gè)數(shù)組,包含了將要添加到Blob對象中的數(shù)據(jù)。數(shù)組元素可以是任意多個(gè)的ArrayBuffer, ArrayBufferView(typed array), Blob, 或者DOMString對象。
-
properties一個(gè)對象,設(shè)置Blob對象的一些屬性。目前僅支持一個(gè)
type屬性,表示Blob的類型。
五、方法
Blob對象有個(gè)很重要的方法-slice(),作用是,可以實(shí)現(xiàn)文件的分割!
具體使用方法如下,和數(shù)組slice相似:
Blob slice(
[可選] long long start,
[可選] long long end,
[可選] DOMString contentType
};
參數(shù)釋義:
-
start開始索引,可以為負(fù)數(shù),語法類似于數(shù)組的
slice方法。默認(rèn)值為0. -
end結(jié)束索引,可以為負(fù)數(shù),語法類似于數(shù)組的
slice方法。默認(rèn)值為最后一個(gè)索引。 -
contentType- 新的Blob對象的MIME類型,這個(gè)值將會(huì)成為新的Blob對象的type屬性的值,默認(rèn)為一個(gè)空字符串。
- 顯然,此方法返回的數(shù)據(jù)格式還是Blob對象,不過是指定范圍復(fù)制的新的Blob對象。注意,如果
start參數(shù)的值比源Blob對象的size屬性值還大,則返回的Blob對象的size值為0,也就是不包含任何數(shù)據(jù)。
- 顯然,此方法返回的數(shù)據(jù)格式還是Blob對象,不過是指定范圍復(fù)制的新的Blob對象。注意,如果
四、舉例
Blob獲取圖片并二進(jìn)制顯示demo
var eleAppend = document.getElementById("forAppend");
window.URL = window.URL || window.webkitURL;
if (typeof history.pushState == "function") {
var xhr = new XMLHttpRequest();
xhr.open("get", "/image/study/s/s256/mm1.jpg", true);
xhr.responseType = "blob";
xhr.onload = function() {
if (this.status == 200) {
var blob = this.response;
var img = document.createElement("img");
img.onload = function(e) {
window.URL.revokeObjectURL(img.src); // 清除釋放
};
img.src = window.URL.createObjectURL(blob);
eleAppend.appendChild(img);
}
}
xhr.send();
} else {
eleAppend.innerHTML = '<p style="color:#cd0000;">瀏覽器不給力,還是早點(diǎn)回去給孩子喂奶吧~</p>';
}
Arraybuffer和Blob的區(qū)別
ArrayBuffer其實(shí)就是一塊連續(xù)內(nèi)存,所以是low-level的。你可以將這塊內(nèi)存映射為某種數(shù)組(TypedArray)或者是自定義的數(shù)據(jù)視圖(DataView),將來如果JS有了Struct(或TypedObject),有可能可以映射為結(jié)構(gòu)體(Struct)或結(jié)構(gòu)體數(shù)組。Blob則是一個(gè)相對high-level的概念,來自于數(shù)據(jù)庫,可以認(rèn)為就是「文件」(所以blob是有文件類型的,即mime type),只不過是脫離具體文件系統(tǒng)的文件(不需要有文件名、文件路徑之類的東西)。Blob對象并不對應(yīng)內(nèi)存,一個(gè)blob引用更像文件句柄,你讀取blob的內(nèi)容,可以是全放進(jìn)一個(gè)ArrayBuffer里,也可以直接得到一個(gè)字符串(如果是文本文件),還可以通過Stream來讀取,特別是blob很大的情況下內(nèi)存也放不下,只能通過流處理。注意,
Blob并不像ArrayBuffer是JS語言內(nèi)置的,而是Web API,Node.js的API里就沒有Blob。這也是為什么MDN說Blob表示的不一定是JavaScript原生格式的數(shù)據(jù)。Blob用于操作二進(jìn)制文件ArrayBuffer用于操作內(nèi)存大白話來說就是ArrayBuffer表達(dá)的是一片可編輯的內(nèi)存,很類似于Node里的Buffer或者其它語言里動(dòng)態(tài)分配的內(nèi)存。里面的數(shù)據(jù)是可讀可寫的。而Blob表示的是一個(gè)做為一個(gè)整體的二進(jìn)制文件,更多的目的是直接使用它
ArrayBuffer和TypedArray,以及Blob的使用
1. 前端使用TypedArray編輯二進(jìn)制
var ab = new ArrayBuffer(32)
var iA = new Int8Array(ab)
iA[0] = 97;//把二進(jìn)制的數(shù)據(jù)的首位改為97 ,97為小寫字母a的ascll碼;
var blob = new Blob([iA], {type: "application/octet-binary"});//把二進(jìn)制的碼轉(zhuǎn)化為blob類型
var url = URL.createObjectURL(blob);
window.open(url)
2. FileReader讀區(qū)blob文件
var ab = new ArrayBuffer(32)
var iA = new Int8Array(ab)
iA[0] = 97
var blob = new Blob([iA], {type: "application/octet-binary"});
var fr = new FileReader();
fr.addEventListener("load", function(ev) {
console.log(ev.target.result);//會(huì)輸出字符:a
});
fr.readAsText(blob)
3. blob轉(zhuǎn)化為typedArray
var ab = new ArrayBuffer(32)
var iA = new Int8Array(ab)
iA[0] = 97
var blob = new Blob([iA], {type: "application/octet-binary"});
var fr = new FileReader();
fr.addEventListener("load", function(ev) {
var abb = ev.target.result;
var iAA = new Int8Array(abb);
console.log(iAA);
});
//把blob文件轉(zhuǎn)化為arraybuffer;
fr.readAsArrayBuffer(blob)
arraybuffer -->> typedarray -->> blob -->> blob通過FileReader轉(zhuǎn)化為 arraybuffer或者text文本或者base64字符串;
arraybuffer和typedarray主要是處理二進(jìn)制, 如果要把blob往二進(jìn)制轉(zhuǎn)換, 必須先把blob轉(zhuǎn)換為arraybuffer, 然后再轉(zhuǎn)換為可以編輯的typedArray;
實(shí)際上, 還有一種比較常用的數(shù)據(jù)類型, base64編碼的數(shù)據(jù), 常用的比如image的base64的編碼, 文本的base64編碼等, 也可以把base64的編碼轉(zhuǎn)化為對應(yīng)的ascll碼,再轉(zhuǎn)化為typearray ,然后再生成blob對象:
4. base64的編碼生成blob
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
//通過atob把base64轉(zhuǎn)化為ascll碼, 然后再把a(bǔ)scll碼轉(zhuǎn)化為字節(jié)碼
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
//u8arr就是2進(jìn)制的數(shù)據(jù)
return new Blob([u8arr], {type:mime});
}