Node.js Buffer
Node.js Buffer 的核心概念,与 Uint8Array 的关系,编码、分配、拼接与切片操作。
#type / concept
#status / growing
#tech / dev / backend
#resource / nodejs
#resource / javascript
[!info] related notes
- 所属 MOC: Node.js MOC
- 相关概念: Node.js Stream
Node.js Buffer
一句话定义
Buffer 是 Node.js 中处理二进制数据的类,底层是固定大小的内存块分配在 V8 堆外。
Buffer vs Uint8Array
| 特性 | Buffer | Uint8Array |
|---|---|---|
| 继承关系 | Buffer 继承自 Uint8Array | TypedArray 原生类型 |
| 内存位置 | 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 支持以下编码:utf8、ascii、latin1、base64、base64url、hex、utf16le
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));
关键区别:
slice和subarray都返回共享内存的视图- 修改视图会影响原始 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()结果不同