接觸node後,少不了會對文件進行操做,因而你可能會遇到如下問題:html
"arrayBuffer"
,那arrayBuffer
是什麼呢?buffer
。好比使用fs.readFile()
去讀文件時,第一個參數的類型是能夠是Buffer
,那Buffer
是什麼呢?TypedArray
,那TypedArray
又是什麼呢?若是你對這三個問題的答案瞭然於心,那麼接下來的文章能夠不用看了。若是有疑問的話,能夠往下看,說不定就能幫你解決疑問。java
首先你須要瞭解一下二進制數組,這對於咱們搞明白上面三個問題很是重要。node
是什麼:用於處理二進制數據的類。es6
爲何存在:javaScript
與顯卡通訊的時候,大量的實時的數據交互,用文本格式須要進行格式轉化,二進制則省去轉化時間。api
和數組的關係:buffer
的實例相似與整數數組,可是buffer
的大小是固定不變的。數組
二進制數組由三類對象組成:網絡
Uint8Array
(無符號 8 位整數)數組視圖, Int16Array
(16 位整數)數組視圖, Float32Array
(32 位浮點數)數組視圖等等。一波硬解答:函數
ArrayBuffer
對象表明原始的二進制數據TypedArray
視圖用來讀寫簡單類型的二進制數據(ArrayBuffer),DataView
視圖用來讀寫複雜類型的二進制數據(ArrayBuffer)。Buffer
類是以更優化和更適合Nodejs的方式實現了Unit8Array
API,意思就是Buffer
類實際上是TypedArray(Unit8Array)
的nodejs實現。至此,上面三個問題應該都解決了。想了解更多的能夠繼續往下看。優化
ArrayBuffer
對象表明儲存二進制數據的一段內存,它不能直接讀寫,只能經過視圖進行操做。ui
ArrayBuffer
也是一個構造函數,能夠分配一段能夠存放數據的連續內存
const buffer = new BufferAarray(12); // 生成一個能夠12個字節的連續內存,每一個字節的默認值是0
複製代碼
以DataView視圖方式讀取
const buffer = new BufferAarray(12);
const dataView = new DataView(buffer); // 對一段12字節的內存創建DataView視圖
dataView.getUnit8(0); // 0 以Unit8方式讀取第一個字節
複製代碼
以TypedArray視圖方式讀取,和DataView不一樣的是DataView是一個構造函數,TypedArray則是一組構造函數
const buffer = new BufferAarray(12);
const x1 = new Unit8Array(buffer); // 創建Unit8Array視圖
const x2 = new Int32Array(buffer); // 創建Int32Array視圖
x1[0] = 1;
x2[0] = 2;
// 因爲兩個視圖是對應的是同一段內存,因此其中一個視圖更改了內存,會影響到另外一個視圖
x1[0]; // 2
複製代碼
ArrayBuffer對象還擁有byteLength屬性和slice方法(此方法是ArrayBuffer對象上惟一能夠讀寫內存的方法)。
ArrayBuffer有一個靜態方法isView,判斷參數是否爲視圖實例。
const buffer = new ArrayBuffer(12);
buffer.byteLength; // 12
buffer.slice(0, 3); // 用法和數組一致,拷貝buffer的前三個字節生成一個新的ArrayBuffer對象
ArrayBuffer.isView(buffer); // false
const dataView = new DataView(buffer);
ArrayBuffer.isView(dataView); // true
複製代碼
因爲視圖的構造函數能夠指定起始位置和長度,因此在同一段內存之中,能夠依次存放不一樣類型的數據,這叫作「複合視圖」。
const buffer = new ArrayBuffer(12);
const a = new Unit8Array(buffer, 0, 1); // 以Unit8Array讀取第一個字節
a[0] = 1;
const b = new Int32Array(buffer, 1, 2); // 以Int32Array讀取第二個字節
b[0] = 2;
複製代碼
視圖是什麼:ArrayBuffer對象能夠存儲多種類型的數據。不一樣類型的數據有不一樣的解讀方式,這就叫視圖
視圖的做用:以指定格式解讀二進制數據
TypedArray一共包含九種類型,每一種都是一個構造函數。(DataView視圖支持除Unit8ClampedArray之外的八種)
名稱 | 佔用字節 | 描述 |
---|---|---|
Int8Array | 1 | 8位有符號整數 |
Uint8Array | 1 | 8位無符號整數 |
Uint8ClampedArray | 1 | 8位無符號整型固定數組(數值在0~255之間) |
Int16Array | 2 | 16位有符號整數 |
Uint16Array | 2 | 16位無符號整數 |
Int32Array | 4 | 32 位有符號整數 |
Uint32Array | 4 | 32 位無符號整數 |
Float32Array | 4 | 32 位 IEEE 浮點數 |
Float64Array | 8 | 64 位 IEEE 浮點數 |
cancat
方法若是一段數據包含多種類型的數據,除了使用複合視圖的方式讀取以外,還可使用DataView視圖讀取。
DataView
視圖提供更多操做選項,並且支持設定字節序。原本,在設計目的上,ArrayBuffer
對象的各類TypedArray
視圖,是用來向網卡、聲卡之類的本機設備傳送數據,因此使用本機的字節序就能夠了;而DataView
視圖的設計目的,是用來處理網絡設備傳來的數據,因此大端字節序或小端字節序是能夠自行設定的。
大端字節序和小端字節序,x68系統使用小端字節序,123456中12比較重要,因此排在後面,存儲順序是563412。大端則相反
一系列get方法用來讀取內存
const buffer = new ArrayBuffer(24);
const dv = new DataView(buffer);
// 接受一個參數
const v1 = dv.getUnit8(0); // 從第一個字節讀取一個8位無符號整數
// 讀兩個字節以上時,須要明確數據的存儲模式(true:小端/false:大端)
const v1 = dv.getUint16(1, true); // 從第二個字節開始,讀取一個16位無符號整數(長度兩個字節)
複製代碼
一些列set方法用來寫入內存
// 接受三個參數,1.字節序號,2.寫入的數據,3.寫入方式(true:小端/false|undeifined:大端)
dv.setInt32(0, 25, false); // 在第一個字節以大端字節序寫入一個值爲25的32位整數
複製代碼
在引入TypedArray以前,js沒有讀取或操做二進制數據流的機制。Buffer類是做爲nodejs API的一部分引入的,用於在TCP流,文件操做系統,以及上下文中與八位字節流進行交互。
如今可使用 TypedArray
, Buffer
類以更優化和更適合 Node.js 的方式實現了 Uint8Array
API。
buffer類的實例相似於從0到255之間的整數數組(其餘整數會經過& 255
操做強制轉換到範圍內)
初始化較慢,可是能保證新建的buffer實例不包含敏感數據
若是size小於或等於buffer.poolsize的一半,則allocUnsafe生成的buffer實例多是從共享的內部內存池分配,allocUnsafeslow則歷來不使用共享的內部內存池
Buffer
實例也是 Uint8Array
實例,可是與 TypedArray
有微小的不一樣。(buffer能夠類比爲視圖)
Buffer.from()
與 TypedArray.from()
有着不一樣的實現。具體來講,typedArray.form()可接受第二個參數爲映射函數,buffer.form()不行
參考文檔: