JS二進(jìn)制文件等數(shù)據(jù)的操作

二進(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ù)。

四、舉例

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});
} 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容