這次帶給大家Node.js Buffer使用詳解,Node.js Buffer使用的注意事項有哪些,下面就是實戰案例,一起來看一下。
Buffer是什麼?
Buffer作為存在於全域物件上,無需引入模組即可使用,你絕對不可以忽略它。
可以理解Buffer是在記憶體中開闢的一片區域,用來存放二進位資料。 Buffer所開闢的是堆外記憶體。
Buffer的應用程式場景有哪些?
流
怎麼理解流呢?流是資料的集合(與資料、字串類似),但是流的資料不能一次獲取到,資料也不會全部load到記憶體中,因此流非常適合大數據處理以及斷斷續續返回chunk的外部來源。流的生產者與消費者之間的速度通常是不一致的,因此需要buffer來暫存一些數據。 buffer大小透過highWaterMark參數指定,預設為16Kb。
儲存需要佔用大量記憶體的資料
Buffer 物件佔用的記憶體空間是不計算在Node.js 進程記憶體空間限制上的,所以可以用來存儲大對象,但是對象的大小還是有限制的。一般情況下32位元系統大約是1G,64位元系統大約是2G。
如何建立Buffer
除了串流自動隱含建立Buffer之外,也可以手動建立Buffer,方式如下:
Buffer中儲存的資料已確定
Buffer.from(obj) // obj支援的類型string, buffer, arrayBuffer, array, or array-like object
注意:Buffer.from不支援傳入數字,如下所示:
Buffer.from(1234); buffer.js:208 throw new errors.TypeError( ^ TypeError [ERR_INVALID_ARG_TYPE]: The "value" argument must not be of type number. Received type number at Function.from (buffer.js:208:11) ...
若要傳入數字可以採用傳入數組的方式:
const buf = Buffer.from([1, 2, 3, 4]); console.log(buf); // <Buffer 01 02 03 04>
但是這種方式存在一個問題,當存入不同的數值的時候buffer中記錄的二進位資料會相同,如下所示:
const buf2 = Buffer.from([127, -1]); console.log(buf2); // <Buffer 7f ff> const buf3 = Buffer.from([127, 255]); console.log(buf3); // <Buffer 7f ff> console.log(buf3.equals(buf2)); // true
當要記錄的一組數全部落在0到255(readUInt8來讀取)這個範圍, 或者全部落在-128到127(readInt8來讀取)這個範圍那麼就沒有問題,否則的話就強烈不推薦使用Buffer.from來保存一組數。因為不同的數字讀取時應該呼叫不同的方法。
Buffer儲存資料未確定
Buffer.alloc、Buffer.allocUnsafe、Buffer.allocUnsafeSlow
Buffer.alloc會用0值填滿已分配的內存,所以相比後兩者速度上要慢,但是也較為安全。當然也可以透過--zero-fill-buffers flag使allocUnsafe、allocUnsafeSlow在分配完記憶體後也進行0值填滿。
node --zero-fill-buffers index.js
當分配的空間小於4KB的時候,allocUnsafe會直接從先前預先分配的Buffer裡面slice空間,因此速度比allocUnsafeSlow要快,當大於等於4KB的時候二者速度相差無異。
// 分配空间等于4KB function createBuffer(fn, size) { console.time('buf-' + fn); for (var i = 0; i < 100000; i++) { Buffer[fn](size); } console.timeEnd('buf-' + fn); } createBuffer('alloc', 4096); createBuffer('allocUnsafe', 4096); createBuffer('allocUnsafeSlow', 4096); // 输出 buf-alloc: 294.002ms buf-allocUnsafe: 224.072ms buf-allocUnsafeSlow: 209.22ms
function createBuffer(fn, size) { console.time('buf-' + fn); for (var i = 0; i < 100000; i++) { Buffer[fn](size); } console.timeEnd('buf-' + fn); } createBuffer('alloc', 4095); createBuffer('allocUnsafe', 4095); createBuffer('allocUnsafeSlow', 4095); // 输出 buf-alloc: 296.965ms buf-allocUnsafe: 135.877ms buf-allocUnsafeSlow: 205.225ms
要謹記一點:new Buffer(xxxx) 方式已經不建議使用了
##Buffer使用
const buf = Buffer.from('test');
console.log(buf.toString('utf8')); // test
console.log(buf.toString('utf8', 0, 2)); // te
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]); console.log(buf.toJSON()); // { type: 'Buffer', data: [ 1, 2, 3, 4, 5 ] }buffer裁剪,裁剪後傳回的新的buffer與原buffer指向同一塊記憶體
buf.slice([start[, end]])
var buf1 = Buffer.from('test'); var buf2 = buf1.slice(1, 3).fill('xx'); console.log("buf2 content: " + buf2.toString()); // xx console.log("buf1 content: " + buf1.toString()); // txxt###buffer拷貝,buffer與陣列不同,buffer的長度一旦確定就不再變化,因此當拷貝的來源buffer比目標buffer大時只會複製部分的值###
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])###範例:###
var buf1 = Buffer.from('abcdefghijkl'); var buf2 = Buffer.from('ABCDEF'); buf1.copy(buf2, 1); console.log(buf2.toString()); //Abcdef######buffer相等判斷,比較的是二進位值######
buf.equals(otherBuffer)###範例:###
const buf1 = Buffer.from('ABC'); const buf2 = Buffer.from('414243', 'hex'); console.log(buf1.equals(buf2)); // true###除了equals之外,compare其實也可以用來判斷是否相等(當結果為0則相等),不過compare更主要的作用是用來對數組內的buffer實例排序。 #########buffer是否包含特定值######
buf.includes(value[, byteOffset][, encoding]) buf.indexOf(value[, byteOffset][, encoding])
示例:
const buf = Buffer.from('this is a buffer'); console.log(buf.includes('this')); // true console.log(buf.indexOf('this')); // 0
写入读取数值
写入方法:
位数固定且超过1个字节的: write{Double| Float | Int16 | Int32| UInt16 | UInt32 }{BE|LE}(value, offset)
位数不固定的: write{Int | UInt}{BE | LE}(value, offset, bytelength) //此方法提供了更灵活的位数表示数据(比如3位、5位)
位数固定是1个字节的: write{Int8 | Unit8}(value, offset)
读取方法:
位数固定且超过1个字节的: read{Double| Float | Int16 | Int32 | UInt16 | UInt32 }{BE|LE}(offset)
位数不固定的: read{Int | UInt}{BE | LE}(offset, byteLength)
位数固定是1个字节的: read{Int8 | Unit8}(offset)
Double、Float、Int16、Int32、UInt16、UInt32既确定了表征数字的位数,也确定了是否包含负数,因此定义了不同的数据范围。同时由于表征数字的位数都超过8位,无法用一个字节来表示,因此就涉及到了计算机的字节序区分(大端字节序与小端字节序)
关于大端小端的区别可以这么理解:数值的高位在buffer的起始位置的是大端,数值的低位buffer的起始位置则是小端
const buf = Buffer.allocUnsafe(2); buf.writeInt16BE(256, 0) console.log(buf); // <Buffer 01 00> buf.writeInt16LE(256, 0) console.log(buf); // <Buffer 00 01>
http://tools.jb51.net/transcoding/hexconvert这里可以查看数值的不同进制之间的转换,如果是大端的话,则直接按顺序(0100)拼接16进制即可,如果是小端则需要调换一下顺序才是正确的表示方式。
buffer合并
Buffer.concat(list[, totalLength]) //totalLength不是必须的,如果不提供的话会为了计算totalLength会多一次遍历
const buf1 = Buffer.from('this is'); const buf2 = Buffer.from(' funny'); console.log(Buffer.concat([buf1, buf2], buf1.length + buf2.length)); // <Buffer 74 68 69 73 20 69 73 20 66 75 6e 6e 79>
清空buffer
清空buffer数据最快的办法是buffer.fill(0)
buffer模块与Buffer的关系
Buffer是全局global上的一个引用,指向的其实是buffer.Buffer
const buffer = require('buffer'); console.log(buffer.Buffer === Buffer); //true
buffer模块上还有其他一些属性和方法
const buffer = require('buffer'); console.log(buffer); { Buffer: { [Function: Buffer] poolSize: 8192, from: [Function: from], alloc: [Function: alloc], allocUnsafe: [Function: allocUnsafe], allocUnsafeSlow: [Function: allocUnsafeSlow], isBuffer: [Function: isBuffer], compare: [Function: compare], isEncoding: [Function: isEncoding], concat: [Function: concat], byteLength: [Function: byteLength], [Symbol(node.isEncoding)]: [Function: isEncoding] }, SlowBuffer: [Function: SlowBuffer], transcode: [Function: transcode], INSPECT_MAX_BYTES: 50, kMaxLength: 2147483647, kStringMaxLength: 1073741799, constants: { MAX_LENGTH: 2147483647, MAX_STRING_LENGTH: 1073741799 } }
上面的kMaxLength与MAX_LENGTH代表了新建buffer时内存大小的最大值,当超过限制值后就会报错
32为机器上是(2^30)-1(~1GB)
64位机器上是(2^31)-1(~2GB)
Buffer释放
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是Node.js Buffer使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!