nodejs -- Buffer



如果想直接查看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

原理圖示

415906299-5749712ec212f.png-64.3kB


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM