Skip to content

Node.js 缓冲器 (Buffers)

纯 JavaScript 针对 Unicode 字符串进行了优化,但在处理原始二进制数据方面传统上缺乏可靠的机制。与网络协议 (TCP, UDP)、文件系统或图像数据交互时,经常需要直接处理字节序列(八位字节)。Node.js 通过内置的 Buffer 类解决了这一需求。

Buffer 实例表示在 V8 JavaScript 引擎堆内存之外分配的固定大小内存块。它们类似于整数数组,其中每个整数表示一个字节(0-255),但提供了专门用于处理二进制数据的方法。

Buffer 类是全局类型,这意味着你无需显式地 require('buffer') 即可使用它。

创建 Buffer(现代且安全的方法)

Section titled “创建 Buffer(现代且安全的方法)”

较旧的 new Buffer() 构造函数已废弃且不安全,因为它可能分配未初始化内存,潜在地暴露敏感数据。请务必使用现代的静态方法:

  • Buffer.alloc(size[, fill[, encoding]]): 创建一个指定 size(以字节为单位)的新的、已初始化(填充零)的 Buffer。这是最安全且通常推荐的方法,当你事先只知道 Buffer 的大小时使用。
  • Buffer.allocUnsafe(size): 创建一个指定 size 的新的、未初始化的 Buffer。这比 Buffer.alloc() 更快,但内存段可能包含旧数据。仅在你确定会立即完全覆盖 Buffer 或性能绝对至关重要时使用此方法。
  • Buffer.from(data[, encoding]): 创建一个新 Buffer,其中包含提供的 data 的副本。data 可以是字符串、另一个 Buffer、一个 ArrayBuffer、一个 TypedArray 或一个字节值 (0-255) 数组。

创建一个填充零的 10 字节 Buffer:

const buf = Buffer.alloc(10);
console.log(buf); // <Buffer 00 00 00 00 00 00 00 00 00 00>

从字节值数组创建一个 Buffer:

const buf = Buffer.from([10, 20, 30, 40, 50]);
console.log(buf); // <Buffer 0a 14 1e 28 32>
console.log(buf[0]); // 10
console.log(buf[4]); // 50

从字符串创建一个 Buffer,使用指定的编码:

// Using default UTF-8 encoding
const bufUtf8 = Buffer.from('Hello World');
console.log(bufUtf8); // <Buffer 48 65 6c 6c 6f 20 57 6f 72 6c 64>
// Using 'hex' encoding
const bufHex = Buffer.from('48656c6c6f', 'hex');
console.log(bufHex.toString('utf8')); // Hello
// Using 'base64' encoding
const bufBase64 = Buffer.from('SGVsbG8gV29ybGQ=', 'base64');
console.log(bufBase64.toString('utf8')); // Hello World

常用的编码包括 'utf8', 'utf16le', 'latin1', 'ascii', 'hex', 'base64', 'base64url', 'ucs2'。

使用 buf.write() 方法将字符串数据写入现有的 buffer 中:

buf.write(string[, offset][, length][, encoding])
  • string: 要写入 buffer 的字符串数据。
  • offset: 在 buffer 内开始写入的索引。默认为 0。
  • length: 要写入的最大字节数。默认为 buffer.length - offset。
  • encoding: 输入 string 的编码。默认为 ‘utf8’。

返回写入的字节数。如果 buffer 没有足够的空间容纳整个字符串(考虑到 offset 和 length),只会写入部分字符串。

const buf = Buffer.alloc(20);
const len = buf.write('Node.js Learning');
console.log(`Bytes written: ${len}`); // Output: Bytes written: 16
console.log(buf.toString()); // Output: Node.js Learning
// Write starting at offset 8
const len2 = buf.write('Buffers', 8, 7, 'utf8'); // Write 'Buffers' over 'Learning'
console.log(`Bytes written (part 2): ${len2}`); // Output: Bytes written (part 2): 7
console.log(buf.toString()); // Output: Node.js Buffersng

使用 buf.toString() 将 buffer 数据解码为字符串:

buf.toString([encoding][, start][, end])
  • encoding: 用于解码的编码。默认为 ‘utf8’。
  • start: 在 buffer 内开始解码的起始索引。默认为 0。
  • end: 在 buffer 内停止解码的结束索引(不包含该索引)。默认为 buffer.length。

返回 buffer 数据(或其中一部分)的解码后字符串表示。

const buf = Buffer.alloc(26);
for (let i = 0; i < 26; i++) {
buf[i] = i + 97; // Fill with ASCII 'a' through 'z'
}
console.log(buf.toString('ascii')); // Outputs: abcdefghijklmnopqrstuvwxyz
console.log(buf.toString('ascii', 0, 5)); // Outputs: abcde
console.log(buf.toString('utf8', 5, 10)); // Outputs: fghij (UTF8 and ASCII are compatible here)
console.log(buf.toString(undefined, 10, 15)); // Encoding defaults to 'utf8', outputs: klmno

buf.toJSON() 方法提供了一个适合序列化的 JSON 表示。

buf.toJSON()

返回一个对象,格式为 { type: 'Buffer', data: [字节值数组] }。注意 JSON.stringify() 在字符串化 Buffer 实例时会隐式调用此方法。

const buf = Buffer.from('Hello');
const json = buf.toJSON();
console.log(json);
// Output: { type: 'Buffer', data: [ 72, 101, 108, 108, 111 ] }
const jsonString = JSON.stringify(buf);
console.log(jsonString);
// Output: "{\"type\":\"Buffer\",\"data\":[72,101,108,108,111]}"

使用静态方法 Buffer.concat() 将多个 Buffer 合并为一个新的 Buffer。

Buffer.concat(list[, totalLength])
  • list: 要连接的 Buffer 实例数组。
  • totalLength (可选): 合并后 buffer 的总长度。提供此参数可以提高性能,因为它避免了额外的循环来计算长度。

返回一个新 Buffer,其中包含 list 中各个 buffer 连接后的数据。

const buffer1 = Buffer.from('Node.js ');
const buffer2 = Buffer.from('is awesome!');
const buffer3 = Buffer.concat([buffer1, buffer2]);
console.log("buffer3 content: " + buffer3.toString());
// Output: buffer3 content: Node.js is awesome!

使用 buf.compare(otherBuffer) 按字典顺序比较两个 buffer 的内容。

buf.compare(otherBuffer);
  • otherBuffer: 与 buf 进行比较的另一个 Buffer 实例。

返回值: 如果 buf 等于 otherBuffer 返回 0,如果 buf 在排序时应排在 otherBuffer 之后返回 1,如果 buf 应排在 otherBuffer 之前返回 -1。

const buffer1 = Buffer.from('ABC');
const buffer2 = Buffer.from('ABCD');
const buffer3 = Buffer.from('ABC');
console.log(buffer1.compare(buffer2)); // Output: -1 (buffer1 comes before buffer2)
console.log(buffer2.compare(buffer1)); // Output: 1 (buffer2 comes after buffer1)
console.log(buffer1.compare(buffer3)); // Output: 0 (buffer1 is the same as buffer3)
// Useful for sorting arrays of buffers
const arr = [buffer2, buffer1, buffer3];
arr.sort(Buffer.compare);
console.log(arr.map(b => b.toString())); // Output: [ 'ABC', 'ABC', 'ABCD' ]

使用 buf.copy() 将数据从一个 buffer (buf) 复制到另一个 buffer (targetBuffer)。

buf.copy(targetBuffer[, targetStart][, sourceStart][, sourceEnd])
  • targetBuffer: 目标 Buffer 对象。
  • targetStart: 在 targetBuffer 中开始写入的索引(默认为 0)。
  • sourceStart: 在源 buf 中开始复制的索引(默认为 0)。
  • sourceEnd: 在源 buf 中停止复制的索引(不包含该索引,默认为 buf.length)。

返回复制的字节数。

const buffer1 = Buffer.from('Source Data');
const buffer2 = Buffer.alloc(15); // Destination buffer
// Copy entire buffer1 to buffer2
buffer1.copy(buffer2);
console.log("buffer2 content: " + buffer2.toString()); // Output: buffer2 content: Source Data
// Copy part of buffer1 ('Data') to buffer2 starting at index 3
const buffer3 = Buffer.alloc(10).fill(' '); // Fill with spaces
buffer1.copy(buffer3, 3, 7, 11); // targetStart=3, sourceStart=7, sourceEnd=11 ('Data')
console.log("buffer3 content: '" + buffer3.toString() + "'"); // Output: buffer3 content: ' Data '

使用 buf.slice() 创建一个新的 Buffer,该 Buffer 引用了原始 buffer 的一部分内存。这是一种浅拷贝——对切片的修改会影响原始 Buffer,反之亦然。

buf.slice([start][, end])
  • start: 切片的起始索引(包含,默认为 0)。
  • end: 切片的结束索引(不包含,默认为 buffer.length)。

返回一个表示原始 buffer 指定部分内存的新 Buffer 实例。

const buffer1 = Buffer.from('Node.js Buffers');
// Create a slice containing 'Buffers'
const buffer2 = buffer1.slice(8, 15);
console.log("buffer2 content: " + buffer2.toString()); // Output: buffer2 content: Buffers
// Modify the slice
buffer2[0] = 0x58; // Change 'B' (0x42) to 'X' (0x58)
console.log("Modified slice: " + buffer2.toString()); // Output: Modified slice: Xuffers
// The original buffer is also changed!
console.log("Original buffer after slice mod: " + buffer1.toString()); // Output: Original buffer after slice mod: Node.js Xuffers

访问 buf.length 属性以获取 buffer 的分配大小(以字节为单位)。

buf.length;

返回为 Buffer 实例分配的字节数。

const buffer = Buffer.from('Example');
// length is the number of bytes, not necessarily characters
console.log("buffer length: " + buffer.length); // Output: buffer length: 7
const bufAlloc = Buffer.alloc(1024);
console.log("bufAlloc length: " + bufAlloc.length); // Output: bufAlloc length: 1024

Buffer 类提供了许多其他方法,用于以不同的字节顺序(字节序)读取和写入特定的数值类型(整数、浮点数、双精度浮点数),填充 buffer,检查编码等。请查阅 Node.js 官方 Buffer 文档以获取完整列表和详细说明。