Node.js 缓冲器 (Buffers)
Node.js - Buffer
Section titled “Node.js - Buffer”纯 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) 数组。
方法 1: Buffer.alloc()
Section titled “方法 1: Buffer.alloc()”创建一个填充零的 10 字节 Buffer:
const buf = Buffer.alloc(10);console.log(buf); // <Buffer 00 00 00 00 00 00 00 00 00 00>方法 2: Buffer.from() 使用数组
Section titled “方法 2: Buffer.from() 使用数组”从字节值数组创建一个 Buffer:
const buf = Buffer.from([10, 20, 30, 40, 50]);console.log(buf); // <Buffer 0a 14 1e 28 32>console.log(buf[0]); // 10console.log(buf[4]); // 50方法 3: Buffer.from() 使用字符串
Section titled “方法 3: Buffer.from() 使用字符串”从字符串创建一个 Buffer,使用指定的编码:
// Using default UTF-8 encodingconst bufUtf8 = Buffer.from('Hello World');console.log(bufUtf8); // <Buffer 48 65 6c 6c 6f 20 57 6f 72 6c 64>
// Using 'hex' encodingconst bufHex = Buffer.from('48656c6c6f', 'hex');console.log(bufHex.toString('utf8')); // Hello
// Using 'base64' encodingconst bufBase64 = Buffer.from('SGVsbG8gV29ybGQ=', 'base64');console.log(bufBase64.toString('utf8')); // Hello World常用的编码包括 'utf8', 'utf16le', 'latin1', 'ascii', 'hex', 'base64', 'base64url', 'ucs2'。
写入 Buffer
Section titled “写入 Buffer”使用 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: 16console.log(buf.toString()); // Output: Node.js Learning
// Write starting at offset 8const len2 = buf.write('Buffers', 8, 7, 'utf8'); // Write 'Buffers' over 'Learning'console.log(`Bytes written (part 2): ${len2}`); // Output: Bytes written (part 2): 7console.log(buf.toString()); // Output: Node.js Buffersng从 Buffer 读取
Section titled “从 Buffer 读取”使用 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: abcdefghijklmnopqrstuvwxyzconsole.log(buf.toString('ascii', 0, 5)); // Outputs: abcdeconsole.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将 Buffer 转换为 JSON
Section titled “将 Buffer 转换为 JSON”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
Section titled “连接 Buffer”使用静态方法 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!比较 Buffer
Section titled “比较 Buffer”使用 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 buffersconst arr = [buffer2, buffer1, buffer3];arr.sort(Buffer.compare);console.log(arr.map(b => b.toString())); // Output: [ 'ABC', 'ABC', 'ABCD' ]复制 Buffer
Section titled “复制 Buffer”使用 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 buffer2buffer1.copy(buffer2);console.log("buffer2 content: " + buffer2.toString()); // Output: buffer2 content: Source Data
// Copy part of buffer1 ('Data') to buffer2 starting at index 3const buffer3 = Buffer.alloc(10).fill(' '); // Fill with spacesbuffer1.copy(buffer3, 3, 7, 11); // targetStart=3, sourceStart=7, sourceEnd=11 ('Data')console.log("buffer3 content: '" + buffer3.toString() + "'"); // Output: buffer3 content: ' Data '切片 Buffer
Section titled “切片 Buffer”使用 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 slicebuffer2[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 XuffersBuffer 长度
Section titled “Buffer 长度”访问 buf.length 属性以获取 buffer 的分配大小(以字节为单位)。
buf.length;返回为 Buffer 实例分配的字节数。
const buffer = Buffer.from('Example');// length is the number of bytes, not necessarily charactersconsole.log("buffer length: " + buffer.length); // Output: buffer length: 7
const bufAlloc = Buffer.alloc(1024);console.log("bufAlloc length: " + bufAlloc.length); // Output: bufAlloc length: 1024Buffer 方法参考
Section titled “Buffer 方法参考”Buffer 类提供了许多其他方法,用于以不同的字节顺序(字节序)读取和写入特定的数值类型(整数、浮点数、双精度浮点数),填充 buffer,检查编码等。请查阅 Node.js 官方 Buffer 文档以获取完整列表和详细说明。