Node.js Buffer

Node.js Buffer 的核心概念,与 Uint8Array 的关系,编码、分配、拼接与切片操作。

#type / concept #status / growing #tech / dev / backend #resource / nodejs #resource / javascript

[!info] related notes

Node.js Buffer

一句话定义

Buffer 是 Node.js 中处理二进制数据的类,底层是固定大小的内存块分配在 V8 堆外。

Buffer vs Uint8Array

特性BufferUint8Array
继承关系Buffer 继承自 Uint8ArrayTypedArray 原生类型
内存位置V8 堆外分配V8 堆内分配
编码支持内置编码转换不支持
性能大数据更快(堆外)小数据够用
API丰富(read/write 系列)标准 TypedArray

Buffer 是 Uint8Array 的子类,可以当 Uint8Array 使用,但有额外的编码和便利方法。

创建 Buffer

// 推荐:指定大小分配(未初始化,内容随机)
const buf = Buffer.alloc(10);        // 10 字节,全部填充 0
const bufUnsafe = Buffer.allocUnsafe(10);  // 10 字节,内容未清零(更快但不安全)

// 从字符串创建
const bufStr = Buffer.from('hello', 'utf8');
const bufBase64 = Buffer.from('aGVsbG8=', 'base64');
const bufHex = Buffer.from('68656c6c6f', 'hex');

// 从数组/ArrayBuffer 创建
const bufArr = Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]);
const bufAb = Buffer.from(new ArrayBuffer(10));

编码支持

Buffer 支持以下编码:utf8asciilatin1base64base64urlhexutf16le

const buf = Buffer.from('你好', 'utf8');
console.log(buf.length);           // 6(每个中文字符 3 字节)
console.log(buf.toString('hex'));   // e4bda0e5a5bd
console.log(buf.toString('base64')); // 5L2g5aW9

// 指定偏移量和长度解码
const partial = buf.toString('utf8', 0, 3); // '你'

拼接 Buffer

// concat:合并多个 Buffer
const buf1 = Buffer.from('Hello');
const buf2 = Buffer.from(' ');
const buf3 = Buffer.from('World');
const merged = Buffer.concat([buf1, buf2, buf3]);
console.log(merged.toString()); // 'Hello World'

// 指定总长度
const mergedWithLen = Buffer.concat([buf1, buf2, buf3], 11);

slice vs subarray

const buf = Buffer.from('Hello World');

// slice:返回视图(共享内存!修改子切片会影响原 Buffer)
const sliced = buf.slice(0, 5);
sliced[0] = 0x48; // 'H' -> 'H'(没变),但如果改别的值会影响原 buf

// subarray:和 slice 行为一致,也是共享内存
const sub = buf.subarray(0, 5);

// 如果需要独立副本,手动复制
const copy = Buffer.from(buf.subarray(0, 5));

关键区别:

  • slicesubarray 都返回共享内存的视图
  • 修改视图会影响原始 Buffer
  • 需要独立副本时用 Buffer.from(view) 创建

读写二进制数据

const buf = Buffer.alloc(8);

// 写入不同类型的数值
buf.writeUInt8(0xFF, 0);           // 无符号 8 位
buf.writeUInt16BE(0x1234, 1);      // 大端序 16 位
buf.writeUInt32LE(0x12345678, 3);  // 小端序 32 位
buf.writeFloatBE(3.14, 4);         // 浮点数

// 读取
console.log(buf.readUInt8(0));        // 255
console.log(buf.readUInt16BE(1));     // 4660
console.log(buf.readUInt32LE(3));     // 305419896

内存注意事项

// allocUnsafe 可能包含旧数据(来自已释放的内存)
// 性能敏感场景才用,且要在写入前确保填充了新数据
const fast = Buffer.allocUnsafe(1024 * 1024);
fast.fill(0); // 手动清零

// Buffer 在堆外分配,不受 V8 堆大小限制
// 但仍然受系统内存限制
console.log(Buffer.poolSize); // 默认 8192 字节

常见误区

  • allocUnsafe 不安全:可能泄露旧内存内容
  • slice/subarray 共享内存:不是独立副本
  • 大端 vs 小端:网络协议通常用大端(BE),x86 用小端(LE)
  • 字符串编码:同一个 Buffer 用不同编码 toString() 结果不同
创建于 2026/5/27 更新于 2026/5/27