Buffer
先備知識
BE LE 分別代表big endian 與small endian(大的數至小的數要從右或從左開始排列)
EX:
Copy Data=0x12345678
Big Endian的系統:
存到記憶體會變成 0x12 0x34 0x56 0x78,最高位元組在位址最低位元,最低位元組在位址最高位元,依次排列
Little Endian的系統:
存到記憶體會變成 0x78 0x56 0x34 0x12,最低位元組在最低位元,最高位元組在最高位元,反序排列
ArrayBuffer vs Buffer
JS ArrayBuffer 與 Node.js Buffer 不同之處在於後者不需要裝進 View 就可以操作
Copy // 分別初始化 Buffer: JS ArrayBuffer 與 Node.js 專屬的 Buffer.alloc
const arrayBuffer = new ArrayBuffer ( 24 );
const nodeBuffer = Buffer .alloc ( 24 );
arrayBuffer[ 0 ] = 23
nodeBuffer[ 0 ] = 23
console .log (arrayBuffer);
console .log (nodeBuffer);
可以看到如下
兩者都可以裝進 View 操作
ArrayBuffer 裝進 view 後稱為 TypedArray
Copy // 分別初始化 Buffer: JS ArrayBuffer 與 Node.js 專屬的 Buffer.alloc
const arrayBuffer = new ArrayBuffer ( 24 );
const nodeBuffer = Buffer .alloc ( 24 );
const arrayBufferView = new Int8Array (arrayBuffer);
const nodeBufferView = new Int8Array (nodeBuffer);
arrayBufferView[ 0 ] = '23'
nodeBufferView[ 0 ] = '23'
console .log (arrayBufferView);
console .log (nodeBufferView);
TypedArray
Node.js Buffer 算是一種 TypedArray 的 instance,所以他才有 slice 與 set 等等方法。
DataView
算是比 TypedArray 更底層一點的,當你想設置 little-endian 或是 big-endian 時可以用
Copy const littleEndian = ( function () {
const buffer = new ArrayBuffer ( 2 );
new DataView (buffer) .setInt16 ( 0 , 256 , true /* littleEndian */ );
// Int16Array uses the platform's endianness.
return new Int16Array (buffer)[ 0 ] === 256 ;
})();
console .log (littleEndian); // true or false
---------------
初始化buffer
Copy const buf = new Buffer([0,0,0,0,0,0])
<Buffer 00 00 00 00 00 00>
寫資料(0到6為offset)
Copy buf.writeUIntBE(12345, 0 , 6)
回傳為<Buffer 00 00 00 00 30 39>
3039為16進位,轉為10進位就是12345
試著改看看offset
Copy buf.writeUIntBE(12345, 0 , 2)
<Buffer 30 39 00 00 00 00>
buf.writeUIntBE(12345, 0 , 4)
<Buffer 00 00 30 39 00 00>
注意:buffer如重複write則原本其他offset的數字還是會存在
發現offset後面的數字先減2後的數字即為前面是00的長度
然後後面不足部分會自動重複最後一個buffer數字(這裡後面重複39)
根據官方說明:Where to start reading. Must satisfy:0 <= offset <= buf.length - 4
所以如果輸入以下會產生錯誤buf.writeUIntBE(12345, 0 , 1),因為6位的buffer-4後至少要offset大於等於2
讀取
試試看以下
Copy buf = Buffer.from([0, 0, 0, 5]);
<Buffer 00 00 00 05>
> buf.readInt32BE(3,4).toString(16)
'5000000'
> buf.readInt32BE(2,4).toString(16)
'50000'
> buf.readInt32BE(1,4).toString(16)
'500'
> buf.readInt32BE(0,4).toString(16)
'5'
> buf.readInt32BE(4,4).toString(16)
'0'
UInt 無號整數的型態名稱為 uint8、uint16、uint32、uint64,顧名思義,使用的長度分別為 8 位元、16 位元、32 位元與 64 位元。
舉例來說,uint8 可儲存的整數範圍為 0 到 255 ,共256個數 因為2**8 (二的八次方為256)
writeUInt8
write如果第一個參數前面沒加0x 他會以為你填入的是十進位來看
因為buffer是以16進位表示,所以int8的意思是8bits的Big endian,一共是2個字 因為(2*4 = 8) 一個16進位為4個bits
Copy var buffLen = 128 ;
var buffer = new Buffer (buffLen);
for ( var i = 0 ; i < buffLen; i += 1 ) {
buffer .writeUInt8 ( 1 , i);
}
console .log (buffer)
writeUInt16BE
(除了8以外其他後面都需要加上BE或LE,包含16和32(沒有64以及以上))
因為buffer是以16進位表示,所以16BE的意思是16bits的Big endian,一共是4個字 因為(4*4 = 16) 一個16進位為4個bits
Copy var buffer = new Buffer (buffLen);
for ( var i = 0 ; i < buffLen; i += 2 ) { // 因為buffer一次寫入會寫入2個bits,所以Int16的話共4個bits所以換下一個時要i += 2
buffer .writeUInt16LE ( 0x0102 , i); // 如果改為buffer.writeUInt16LE(0x010203, i); 會出現outbound錯誤
}
console .log (buffer)
writeUInt32BE
因為buffer是以16進位表示,所以32BE的意思是32bits的Big endian,一共是8個字 因為(8*4 = 32) 一個16進位為4個bits
Copy var buffLen = 12 ; //記得要配給他4的倍數 因為Int32 在buffer一次寫入會寫四個字
var buffer = new Buffer (buffLen);
for ( var i = 0 ; i < buffLen; i += 4 ) {
buffer .writeUInt32BE ( 0x01020304 , i);
}
console .log (buffer)
使用Uint或Int
(sign 與 unsign)
Copy var buffLen = 12 ;
var buffer = new Buffer (buffLen);
for ( var i = 0 ; i < buffLen; i += 1 ) {
buffer .writeInt8 ( - 1 , i); //這裡可成功編譯
}
console .log (buffer)
但如果把它換成unsign,如同以下,將會因為unsign不可接受負數,所以出現out bound錯誤
Copy buffer.writeUInt8(-1, i);
https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
UTF8、ASCII、Node.js Buffer
ACSII table: http://www.asciitable.com/
UTF-8 table: https://www.utf8-chartable.de/
UTF-8, unicode 都是在擴充原本 ASCII 不夠的編碼。
以下面為例,分別為 ascii 與 utf-8
在原本 ascii 就有的編碼在utf-8也會是相同的 hex (十六進位), dec (十進位)
接著以 Node.js Buffer 來看
Copy > Buffer .from ( '-' )
< Buffer 2d>
> Buffer.from('-')[0]
45
可以看到原本是以 16 進位表示,但最後把 buffer 單獨拿出來後會是以 10 進位
formidable 在 parse form-data 時也是使用 buffer 方式處理
https://github.com/node-formidable/formidable/blob/master/src/parsers/Multipart.js
Form-data 換行字元
CRLF hex 為 0d, 0a