如果想直接查看7.x文檔的中文API,直接搜索相關內容即可。
Buffer 對象的基本概念
Buffer對象是一個典型的JavaScript與C++的結合模塊,它性能相關的部分由C++來實現,非性能相關的部分由JavaScript來實現。
JS引擎本身是沒有操作文件和數據權限的,但是Node可以直接運行在服務端,也就是說如果實現了與C++底層的對接,就可以去間接的去操作系統文件和數據了。在Node中,通過process對象提供的binging方法就可以完成JS與C++的對接。從源碼也可以看出,關於Buffer.js的第一句代碼:
const binding = process.binding('buffer');
// 在Node中不僅僅是Buffer對象,還有fs等對象都是這樣實現和C++對接的。
Buffer對象有點類似js中的數組,但是它的元素是16進制的兩位數,即為0到255的數值(8位無符號整形Uint8Array),並且可以通過length屬性訪問其長度。
- 值得注意的是,當給buffer元素指定一個小於0或者大於255或者是小數的時候會有一些特別的地方:
* 如果元素賦值小於0,那么該值逐次加上256,直到得到一個0到255的整數。
* 如果元素賦值大於255,那么該值會逐次減去256,直到得到一個0到255的整數。
* 如果是元素賦值是一個小數,那么會舍去小數部分,然后執行上面的兩條規則。
Buffer的內存分配原理
Node中Buffer對象的內存分配不是在V8的堆內存中,而是Node在C++層面實現內存申請的。然后申請來的內存是在JavaScript的層面上進行管理的。
為了高效的管理內存,Node采用了slab動態內存管理機制。大可不必在乎這幾個字符是什么意思,你就簡單的去理解成:slab就是一個分配好的內存區域,也就是你使用Buffer對象傳入一個指定的size就申請了一塊內存。然后slab具有下面的3種狀態:
- empty: 初次被創建,還沒有被分配數據
- partial: 部分空間被分配,並沒有完全分配
- full: 完全被分配
- 另外Node會根據當前申請的內存大小將Buffer對象進行分類,如果(這里以第一次申請為例)申請的內存大小小於4k,那么就會存入初始化的slab單元中,即查閱各種資料所謂的8k池,當接下來繼續申請的內存大小仍然小於4k並且當前第一個初始化的8k池空間足夠的情況下就會繼續存入第一個初始化的8k池。
- 打個比方:如果被初始化的8k池的空間剩余2k,這個時候再去申請一個大於2k並且小於4k的內存空間,就會去新申請一個slab單元空間,上次初始化的slab單元的剩余2k內存就會被浪費掉,無法再使用。
- 如果申請的內存大於4k那么就不會走8k池,而是node直接通過C++層面去申請一個獨占的slab單元空間。
- 最后說明一下:無論是哪種情況,最后得到的Buffer對象都是JavaScript層面的,也就是可以被V8的垃圾回收機制所管理。這中間其實Node做了大量的工作,最主要的就是把JS和C++結合起來。
上面這段話也是我個人理解了好久總結的,可能還是有不對的地方,其中一個點就非常讓人疑惑,命名是8k的大小,為什么用4k作為分界點。源碼上也是這么體現的。或許是人為規定?
以下是使用8k池的API和條件:
- Buffer.allocUnsafe 傳入的數據大小 (0 < size < 4 * 1024)
- Buffer.concat 傳入的數據大小 (0 < size < 4 * 1024)
- Buffer.from 參數不為一個 ArrayBuffer 實例 並且 傳入的數據大小 (0 < size < 4 * 1024)
另外還有個不再使用的 new Buffer() 方式,同樣參數不可以是 ArrayBuffer 實例。
其實我也不明白為什么出現了slab這種動態內存管理機制,按照字面說明的意思就是使用這種機制,可以更高效。我想象了一下,如果再去對根本原因追究下去可能就會要去接觸更底層的知識。反之我想了想,即使我去了解了這種機制,應該也沒有太多的意義,所以這里就不再追尋下去了。
關於我是怎么知道上面這些的?
可以看幾段關鍵的Buffer.js源碼,其實無論使用哪個方法初始化Buffer對象最終都會走進這幾個函數:
Buffer.poolSize = 8 * 1024; // 設定8k池
// 分別對應 8k 已使用的大小partial 和ArrayBuffer對象
var poolSize, poolOffset, allocPool;
class FastBuffer extends Uint8Array {
constructor(arg1, arg2, arg3) {
super(arg1, arg2, arg3);
}
}
// 下面的Buffer也就是Buffer的構造函數,這里沒有復制
// 你只需要知道Buffer是構造函數,不是憑空出來的就行
FastBuffer.prototype.constructor = Buffer;
Buffer.prototype = FastBuffer.prototype;
/*
這個函數便是直接通過C++層面來申請內存
*/
function createUnsafeBuffer(size) {
//FastBuffer繼承自Uint8Array,這里並沒有復制這段代碼
//你只需要知道這一點足夠了。
//通過這段代碼就知道為什么Buffer儲存的是8位
return new FastBuffer(createUnsafeArrayBuffer(size));
}
// 調用 ArrayBuffer 構造接口
function createUnsafeArrayBuffer(size) {
zeroFill[0] = 0;
try {
return new ArrayBuffer(size);
} finally {
zeroFill[0] = 1;
}
}
// 作用:對上面的變量進行初始化,allocPool 作為中間變量指向ArrayBuffer實例。
function createPool() {
poolSize = Buffer.poolSize;
allocPool = createUnsafeArrayBuffer(poolSize);
poolOffset = 0; // 用來存儲使用量
}
createPool(); // 一上來就初始化一個8k池,這樣更可以更高效的進行第一次內存的申請
function allocate(size) {
if (size <= 0) {
return new FastBuffer();
}
// 這里可以明確看出來,什么情況走8k池
// Buffer.poolSize >>> 1 相當於 parseFlot(a/2)
// 例如 9 >>> 1 = 4
if (size < (Buffer.poolSize >>> 1)) {
if (size > (poolSize - poolOffset))
createPool();
var b = new FastBuffer(allocPool, poolOffset, size);
poolOffset += size;
alignPool();
return b;
} else {
// 如果調用這個函數的API申請的內存大小大於4k
// 就會直接去C++層面申請內存
return createUnsafeBuffer(size);
}
}
可以看出如果走的是createUnsafeBuffer()則不會經過8k池,若走 allocate() 函數,當傳入的數據大小小於 Buffer.poolSize 有符號右移 1 位后的結果(相當於將該值除以 2 再向下取整,為 4 KB),才會使用到 8KB 池(若當前池剩余空間不足,則創建一個新的slab單元,並將allocPool指向新池)。
關於更多API源碼可以參閱 Buffer.js
原理圖示
Buffer 對象的API中文文檔 (7.x)
凡是相關API源碼中出現的 assertSize(size) 方法都是做這么一件事:判斷參數size的類型以及大小,會對小於0以及大於最大長度和非數字進行拋出異常處理。
buffer的初始化方式
- 在Node 6.0以前,直接使用new Buffer,但是這種方式存在兩個問題:
* 參數復雜: 內存分配,還是內存分配+內容寫入,需要根據參數來確定
* 安全隱患: 分配到的內存可能還存儲着舊數據,這樣就存在安全隱患
// 本來只想申請一塊內存,但是里面卻存在舊數據
const buf1 = new Buffer(10) // <Buffer 90 09 70 6b bf 7f 00 00 50 3a>
// 一不小心,舊數據就被讀取出來了
buf1.toString() // '�\tpk�\u0000\u0000P:'
為了解決上述問題,Buffer提供了Buffer.from、Buffer.alloc、Buffer.allocUnsafe、Buffer.allocUnsafeSlow四個方法來申請內存。
Class Method: Buffer.alloc(size[, fill[, encoding]])
用來申請指定大小的內存空間
- size,指定buffer的長度,但不能超過buffer.kMaxLength,若不是數字則報錯。
- fill,指定初始化buffer的值,默認為0。
- encoding,如果fill是字符串,則該參數指定fill的編碼,默認'utf8'。
// 申請5個字節的內存
const buf = Buffer.alloc(5);
// Prints: <Buffer 00 00 00 00 00>
// 默認使用0進行填充
console.log(buf);
const buf = Buffer.alloc(5, 'a');
// Prints: <Buffer 61 61 61 61 61>
console.log(buf);
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
// Prints: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
console.log(buf);
源碼:
Buffer.alloc = function(size, fill, encoding) {
assertSize(size);
if (size > 0 && fill !== undefined) {
if (typeof encoding !== 'string')
encoding = undefined;
return createUnsafeBuffer(size).fill(fill, encoding);
}
return new FastBuffer(size);
};
Class Method: Buffer.allocUnsafe(size)
size參數指定buffer的大小,該方法返回一個沒有初始化的buffer,因此可能還保留有敏感的數據,造成信息的泄漏,建議使用buffer.fill(0)函數初始化buffer。
const buf = Buffer.allocUnsafe(10);
// Prints: (contents may vary): <Buffer a0 8b 28 3f 01 00 00 00 50 32> 可以看出是有數據的!
console.log(buf);
buf.fill(0);
// Prints: <Buffer 00 00 00 00 00 00 00 00 00 00>
console.log(buf);
源碼:
Buffer.allocUnsafe = function(size) {
assertSize(size);
return allocate(size);
};
Class Method: Buffer.allocUnsafeSlow(size)
直接通過c++進行內存分配;不會進行舊值填充。除了這兩點與Buffer.allocUnsafe(size)的其他特性一樣。
// 從c++模塊層面直接申請內存
const buf4 = Buffer.allocUnsafeSlow(10);
console.log(buf4); //<Buffer 00 00 00 00 00 00 00 00 86 00> // 不一定是什么數據
源碼:
Buffer.allocUnsafeSlow = function(size) {
assertSize(size);
return createUnsafeBuffer(size);
};
Class Method: Buffer.from(array)
接收一個數組作為參數,會將數組內的值轉化為16進制。
const bufArr = Buffer.from([1,2,3]);
console.log(bufArr); // <Buffer 01 02 03>
源碼:
function fromArrayLike(obj) {
const length = obj.length;
const b = allocate(length);
for (var i = 0; i < length; i++)
b[i] = obj[i];
return b;
}
function fromObject(obj) {
if (isUint8Array(obj)) {
const b = allocate(obj.length);
if (b.length === 0)
return b;
binding.copy(obj, b, 0, 0, obj.length);
return b;
}
if (obj) {
if ('length' in obj || isArrayBuffer(obj.buffer) ||
isSharedArrayBuffer(obj.buffer)) {
if (typeof obj.length !== 'number' || obj.length !== obj.length) {
return new FastBuffer();
}
return fromArrayLike(obj);
}
if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
return fromArrayLike(obj.data);
}
}
throw new TypeError(kFromErrorMsg);
}
Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]])
接收一個arrayBuffer實例並且初始化,二者會共享內存。
- arrayBuffer: ArrayBuffer或者TypedArray的實例
- byteOffset: 接收一個整數,默認值0,用來指定從哪里開始復制arrayBuffer的數據。
- length: 接收一個整數,用來指定復制數據的長度,默認值是 總長度 - byteOffset。
let arrBuf = new ArrayBuffer(12);
let arr32 = new Uint32Array(arrBuf);
arr16[0] = 600;
let bf = Buffer.from(arr32);
console.log(bf); // <Buffer 58 00 00> 這里buffer的長度只有3,這是因為32為無符號整形每個站四個字節
// 也可以直接聲明長度為多少 TypeArray 對象
let arr8 = new Uint8Array(10);
arr8[0] = 1000;
let bf = Buffer.from(arr8);
console.log(bf); // <Buffer e8 00 00 00 00 00 00 00 00 00>
源碼:
function fromArrayBuffer(obj, byteOffset, length) {
byteOffset = internalUtil.toInteger(byteOffset);
const maxLength = obj.byteLength - byteOffset;
if (maxLength < 0)
throw new RangeError("'offset' is out of bounds");
if (length === undefined) {
length = maxLength;
} else {
length = internalUtil.toLength(length);
if (length > maxLength)
throw new RangeError("'length' is out of bounds");
}
return new FastBuffer(obj, byteOffset, length);
}
Class Method: Buffer.from(buffer)
將已經有的buffer復制一份到新的buffer對象,不再是共享同一塊內存。
- buffer: 接收一個 buffer 對象,作為參數。
const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1);
buf1[0] = 0x61;
// Prints: auffer
console.log(buf1.toString());
// Prints: buffer
console.log(buf2.toString());
源碼同上。
Class Method: Buffer.from(string[, encoding])
接收一個字符串作為參數,轉換為buffer對象.
- string: 字符串參數
- encoding: 可選,用來指定轉換為buffer對象后的編碼格式,默認'utf8'。
const buf1 = Buffer.from('this is a tést');
// Prints: this is a tést 默認 utf8
console.log(buf1.toString());
// Prints: this is a tC)st
console.log(buf1.toString('ascii'));
const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
// Prints: this is a tést // 指定為16進制格式
console.log(buf2.toString());
源碼:
function fromString(string, encoding) {
if (typeof encoding !== 'string' || encoding === '')
encoding = 'utf8';
if (!Buffer.isEncoding(encoding))
throw new TypeError('"encoding" must be a valid string encoding');
if (string.length === 0)
return new FastBuffer();
var length = byteLength(string, encoding);
if (length >= (Buffer.poolSize >>> 1))
return binding.createFromString(string, encoding);
if (length > (poolSize - poolOffset))
createPool();
var b = new FastBuffer(allocPool, poolOffset, length);
var actual = b.write(string, encoding);
if (actual !== length) {
// byteLength() may overestimate. That’s a rare case, though.
b = new FastBuffer(allocPool, poolOffset, actual);
}
poolOffset += actual;
alignPool();
return b;
}
Buffer 的屬性
Class Property: Buffer.poolSize: 緩沖區大小,默認8k。
Class Property: buffer.kMaxLength: 緩沖區最大值,32位系統為1GB,64位系統為2GB。
可以使用 buf.length 查看Buffer對象的字節長度,這里需要注意的是字符長度不同於字節長度,比如一個中文代表一個字符長度,但是在utf8編碼格式下有3個字節長度。
const buf1 = Buffer.from('愛');
console.log(buf1.length); // 3
console.log(buf1); // <Buffer e7 88 b1>
Buffer 的常用方法
Buffer對象提供了一些常用的工具方法,下面對一些常用的API進行記錄和總結,方便日后查用。(基於7.x文檔)
buf.toString([encoding[, start[, end]]])
將Buffer對象轉為字符串
- encoding: 指定要轉換為字符串的編碼格式,默認為utf8。
- start: 指定Buffer起始位置,包括起始位置。
- end: 指定Buffer的結束位置,不包括結束位置。
const buf1 = Buffer.allocUnsafe(26);
for (let i = 0 ; i < 26 ; i++) {
// 97 is the decimal ASCII value for 'a'
buf1[i] = i + 97;
}
// Prints: abcdefghijklmnopqrstuvwxyz
console.log(buf1.toString('ascii'));
// Prints: abcde
console.log(buf1.toString('ascii', 0, 5));
const buf2 = Buffer.from('tést');
// Prints: 74c3a97374
console.log(buf2.toString('hex'));
// Prints: té
console.log(buf2.toString('utf8', 0, 3));
// Prints: té
console.log(buf2.toString(undefined, 0, 3));
Class Method: Buffer.byteLength(string[, encoding])
獲取字符串的實際的字節長度
- string: 要獲取的字符串
- encoding: 可選,以指定的編碼格式,默認utf8
const str = '把妹兒';
let len = Buffer.byteLength(str);
console.log(`${str} 的長度是${str.length},字節長度是${len}`);
// 把妹兒 的長度是3,字節長度是9
Class Method: Buffer.compare(buf1, buf2)
比較當前緩沖區和另一個緩沖區的大小,相等返回0,小於返回-1,大於返回1。
const buf1 = Buffer.from('1234');
const buf2 = Buffer.from('0123');
const arr = [buf1, buf2];
// Prints: [ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ]
// (This result is equal to: [buf2, buf1])
console.log(arr.sort(Buffer.compare));
let buf1 = Buffer.from('abc');
let buf2 = Buffer.from('abcb');
let result = Buffer.compare(buf1, buf2);
console.log(result); // -1
Class Method: Buffer.concat(list[, totalLength])
將多個buffer合並在一起,並返回一個新的buffer實例,參數totalLength為指定的buffers的長度總和,如果不提供該值,函數內部會循環去獲取每一個buffer的長度,然后進行拼接,因此為了速度,最好指定一個總長度。
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.alloc(14);
const buf3 = Buffer.alloc(18);
const totalLength = buf1.length + buf2.length + buf3.length;
// Prints: 42
console.log(totalLength);
const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
// Prints: <Buffer 00 00 00 00 ...>
console.log(bufA);
// Prints: 42
console.log(bufA.length);
Class Method: Buffer.isBuffer(obj)
判斷一個對象是否為Buffer對象,是返回true,非返回false。
Class Method: Buffer.isEncoding(encoding)
判斷是否為可用的編碼格式,如果可用返回true,否則返回false。
let orIf = Buffer.isEncoding('utf-16le');
console.log(orIf); // true
// 源碼
Buffer.isEncoding = function(encoding) {
switch ((encoding + '').toLowerCase()) {
case 'hex':
case 'utf8':
case 'utf-8':
case 'ascii':
case 'binary':
case 'base64':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
case 'raw':
return true;
default:
return false;
}
};
buffer.transcode(source, fromEnc, toEnc)
此方法不屬於全局方法,使用之前需要 require('buffer'),用於將指定的Buffer對象從一種編碼格式轉換為另外一種。暫時沒發現有什么用...,當指定的編碼無法轉換的時候會使用 ? 代替。
const buffer = require('buffer');
const newBuf = buffer.transcode(Buffer.from('€'), 'utf8', 'ascii');
console.log(newBuf.toString('ascii'));
// Prints: '?'
buf[index]
通過下標獲取或者設置Buffer對象對應的單個字節。
const str = 'Node.js';
const buf = Buffer.allocUnsafe(str.length);
for (let i = 0; i < str.length ; i++) {
buf[i] = str.charCodeAt(i);
}
// Prints: Node.js
console.log(buf.toString('ascii'));
buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])
與Buffer.compare()功能一樣,但是可以指定目標和源目標的起始和結束位置。
- target: 要比較的Buffer對象。
- targetStart: buf的起始位置,默認值為0。
- targetEnd: buf的結束位置,當targetStart為undefined的時候,不包括結束位置,默認值為buf.length。
- sourceStart: 源Buffer對象的起始位置,當targetStart為undefined的時候,默認值為0。
- sourceEnd: 源Buffer對象的結束位置,不包括結束位置,當targetStart為undefined的時候,默認值為source.length。
- 如果target與source相等,那么返回0。
- 如果target比較source在前面,那么返回1。
- 如果target比較source在后面,那么返回-1。
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
const buf3 = Buffer.from('ABCD');
// Prints: 0
console.log(buf1.compare(buf1));
// Prints: -1
console.log(buf1.compare(buf2));
// Prints: -1
console.log(buf1.compare(buf3));
// Prints: 1
console.log(buf2.compare(buf1));
// Prints: 1
console.log(buf2.compare(buf3));
// Prints: [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
// (This result is equal to: [buf1, buf3, buf2])
console.log([buf1, buf2, buf3].sort(Buffer.compare));
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
將buf的數據拷貝到target上面,是將數據進行復制,所以是兩個不同的內存空間。
- target: 被粘貼的目標Buffer對象。
- targetStart: 被粘貼目標的起始位置。
- sourceStart: 源Buffer對象的起始位置。
- sourceEnd: 源Buffer對象的結束位置,不包括結束位。
const buf1 = Buffer.allocUnsafe(26);
const buf2 = Buffer.allocUnsafe(26).fill('!');
for (let i = 0 ; i < 26 ; i++) {
// 97 is the decimal ASCII value for 'a'
buf1[i] = i + 97;
}
buf1.copy(buf2, 8, 16, 20);
// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
console.log(buf2.toString('ascii', 0, 25));
測方法還可以從將自己的數據復制給自己:
const buf = Buffer.allocUnsafe(26);
for (let i = 0 ; i < 26 ; i++) {
// 97 is the decimal ASCII value for 'a'
buf[i] = i + 97;
}
buf.copy(buf, 0, 4, 10);
// Prints: efghijghijklmnopqrstuvwxyz
console.log(buf.toString());
buf.entries()
對當前Buffer對象創建並返回一個iterator接口,這樣就可以使用for...of...循環進行遍歷,返回對應的鍵值對。
const buf = Buffer.from('buffer');
// Prints:
// [0, 98]
// [1, 117]
// [2, 102]
// [3, 102]
// [4, 101]
// [5, 114]
for (const pair of buf.entries()) {
console.log(pair);
}
buf.equals(otherBuffer)
用來比較兩個Buffer對象是否相等,返回值為布爾值。
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex');
const buf3 = Buffer.from('ABCD');
// Prints: true
console.log(buf1.equals(buf2));
// Prints: false
console.log(buf1.equals(buf3));
buf.fill(value[, offset[, end]][, encoding])
以指定的內容填充Buffer對象。如果傳入參數不是一個字符串或者整數,那么會強制轉換為32位無符號整型Uint32。如果填充的數據是個多字節的,那么只會取出第一個字節進行填充。
- value: 要填充的內容。
- offset: 可以指定起始填充位置。
- end: 指定結束填充位置。
- encoding: 指定填充字符的編碼,默認為utf8。
const b = Buffer.allocUnsafe(50).fill('h');
// Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
console.log(b.toString());
// Prints: <Buffer c8 a2 c8>
console.log(Buffer.allocUnsafe(3).fill('\u0222'));
buf.indexOf(value[, byteOffset][, encoding])
用來查找指定value的起始位置,如果找到了返回當前位置,如果沒找到就返回-1,和字符串的indexOf行為類似。
- value: 可以接收 字符串、Buffer對象、整數類型。
- byteOffset: 指定查找的起始位置,默認0。
- encoding: 如果參數是字符串,可以指定其編碼類型,默認utf8。
const buf = Buffer.from('this is a buffer');
// Prints: 0
console.log(buf.indexOf('this'));
// Prints: 2
console.log(buf.indexOf('is'));
// Prints: 8
console.log(buf.indexOf(Buffer.from('a buffer')));
// Prints: 8
// (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(97));
// Prints: -1
console.log(buf.indexOf(Buffer.from('a buffer example')));
// Prints: 8
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
// Prints: 4
console.log(utf16Buffer.indexOf('\u03a3', 0, 'ucs2'));
// Prints: 6
console.log(utf16Buffer.indexOf('\u03a3', -4, 'ucs2'));
buf.lastIndexOf(value[, byteOffset][, encoding])
從后向前查找指定的數據內容,可字符串的lastIndexOf特性一樣。
- value: 可以接收 字符串、Buffer對象、整數類型。
- byteOffset: 指定查找的起始位置,默認buf.length - 1。
- encoding: 如果參數是字符串,可以指定其編碼類型,默認utf8。
const buf = Buffer.from('this buffer is a buffer');
// Prints: 0
console.log(buf.lastIndexOf('this'));
// Prints: 17
console.log(buf.lastIndexOf('buffer'));
// Prints: 17
console.log(buf.lastIndexOf(Buffer.from('buffer')));
// Prints: 15
// (97 is the decimal ASCII value for 'a')
console.log(buf.lastIndexOf(97));
// Prints: -1
console.log(buf.lastIndexOf(Buffer.from('yolo')));
// Prints: 5
console.log(buf.lastIndexOf('buffer', 5));
// Prints: -1
console.log(buf.lastIndexOf('buffer', 4));
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
// Prints: 6
console.log(utf16Buffer.lastIndexOf('\u03a3', undefined, 'ucs2'));
// Prints: 4
console.log(utf16Buffer.lastIndexOf('\u03a3', -5, 'ucs2'));
buf.includes(value[, byteOffset][, encoding])
與indexOf功能類似,用來查找指定數據,返回布爾值。
- value: 可以接收 字符串、Buffer對象、整數類型。
- byteOffset: 指定查找的起始位置,默認0。
- encoding: 如果參數是字符串,可以指定其編碼類型,默認utf8。
const buf = Buffer.from('this is a buffer');
// Prints: true
console.log(buf.includes('this'));
// Prints: true
console.log(buf.includes('is'));
// Prints: true
console.log(buf.includes(Buffer.from('a buffer')));
// Prints: true
// (97 is the decimal ASCII value for 'a')
console.log(buf.includes(97));
// Prints: false
console.log(buf.includes(Buffer.from('a buffer example')));
// Prints: true
console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
// Prints: false
console.log(buf.includes('this', 4));
buf.keys()
創建並返回 Buffer 對象的 iterator 的 key。
const buf = Buffer.from('buffer');
// Prints:
// 0
// 1
// 2
// 3
// 4
// 5
for (const key of buf.keys()) {
console.log(key);
}
buf.values()
創建並返回 Buffer 對象的 iterator 的 value。
const buf = Buffer.from('buffer');
// Prints:
// 98
// 117
// 102
// 102
// 101
// 114
for (const value of buf.values()) {
console.log(value);
}
// Prints:
// 98
// 117
// 102
// 102
// 101
// 114
for (const value of buf) {
console.log(value);
}
buf.toJSON()
將Buffer轉為JSON對象並返回,也可以隱式的使用JSON.stringify來代替此方法。
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
// Prints: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);
// Prints: { type: 'Buffer', data: [ 98, 117, 102, 102, 101, 114 ] }
console.log(buf.toJSON());
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer'
? Buffer.from(value.data)
: value;
});
// Prints: <Buffer 01 02 03 04 05>
console.log(copy);
源碼:
Buffer.prototype.toJSON = function() {
return {
type: 'Buffer',
data: Array.prototype.slice.call(this, 0)
};
};
buf.write(string[, offset[, length]][, encoding])
在指定的位置以指定的編碼將字符串寫入Buffer對象,如果寫入的字符串的字節數大於Buffer對象的大小,那么就會被截取。另外如果指定的字符編碼不支持是無法寫入的。
- string: 字符串類型的參數。
- offset: 指定寫入的起始位置,默認是0。
- length: 要寫入到Buffer對象的長度,默認是buf.length -- length。
- encoding: 指定字符的編碼格式,默認utf8。
const buf = Buffer.allocUnsafe(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
// Prints: 12 bytes: ½ + ¼ = ¾
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
還有一些不常用的API,請自行參閱英文文檔。
https://nodejs.org/dist/latest-v7.x/docs/api/buffer.html