Node.js Buffer
二进制数据的容器:创建、读写、编码转换、拼接与切片。
Key PointsBuffer 是定长的字节数组,`slice` 共享内存,`Buffer.from` 才复制。
创建
JavaScript
// 从字符串(最常用)
const b1 = Buffer.from('你好', 'utf8');
console.log(b1);
console.log(b1.length);
// 分配并清零
const b2 = Buffer.alloc(4);
// 分配不清零(更快,但可能含旧数据)
const b3 = Buffer.allocUnsafe(4);
// 从数组
const b4 = Buffer.from([0x48, 0x69]);
console.log(b4.toString());Output
<Buffer e4 bd a0 e5 a5 bd>
6
Hi「你好」两个汉字在 UTF-8 里各占 3 字节,所以长度是 6 而不是 2。这是 Buffer 和字符串最直观的差别。
编码
JavaScript
const b = Buffer.from('hello');
console.log(b.toString('hex'));
console.log(b.toString('base64'));
console.log(Buffer.from('aGVsbG8=', 'base64').toString('utf8'));Output
68656c6c6f
aGVsbG8=
hello| Encoding | Typical use |
|---|---|
utf8 | 文本、JSON |
hex | 哈希、密钥、调试 |
base64 | 把二进制塞进 JSON / URL / 邮件 |
latin1 | 单字节老协议 |
utf16le | Windows 内部字符串 |
读写与拼接
JavaScript
const b = Buffer.alloc(8);
b.writeUInt32BE(0xdeadbeef, 0);
b.writeUInt32LE(0x01020304, 4);
console.log(b.toString('hex'));
console.log(b.readUInt32BE(0).toString(16));
const joined = Buffer.concat([Buffer.from('foo'), Buffer.from('bar')]);
console.log(joined.toString());Output
deadbeef04030201
deadbeef
foobarslice 共享内存
JavaScript
const a = Buffer.from('abcdef');
const s = a.subarray(0, 3); // 或 slice,效果一样
s[0] = 0x41; // 'A'
console.log(a.toString()); // 原 Buffer 被改了Output
Abcdefsubarray / slice do not copy — they return a view. For an independent copy use Buffer.from(a.subarray(0, 3)). In network parsing this causes the confusing "changed the slice, original changed too" bug.大文件不要一次读完
Buffer has a length cap (about 4 GB on 64-bit, buffer.constants.MAX_LENGTH). For hundreds of MB of logs or large uploads, use Streams to process in chunks — see the next chapter.
创建
JavaScript
// 从字符串(最常用)
const b1 = Buffer.from('你好', 'utf8');
console.log(b1);
console.log(b1.length);
// 分配并清零
const b2 = Buffer.alloc(4);
// 分配不清零(更快,但可能含旧数据)
const b3 = Buffer.allocUnsafe(4);
// 从数组
const b4 = Buffer.from([0x48, 0x69]);
console.log(b4.toString());Output
<Buffer e4 bd a0 e5 a5 bd>
6
Hi"你好" takes 3 bytes per character in UTF-8, so the length is 6, not 2. That is the most direct difference between a Buffer and a string.
编码
JavaScript
const b = Buffer.from('hello');
console.log(b.toString('hex'));
console.log(b.toString('base64'));
console.log(Buffer.from('aGVsbG8=', 'base64').toString('utf8'));Output
68656c6c6f
aGVsbG8=
hello| 编码 | 典型用途 |
|---|---|
utf8 | 文本、JSON |
hex | 哈希、密钥、调试 |
base64 | 把二进制塞进 JSON / URL / 邮件 |
latin1 | 单字节老协议 |
utf16le | Windows 内部字符串 |
读写与拼接
JavaScript
const b = Buffer.alloc(8);
b.writeUInt32BE(0xdeadbeef, 0);
b.writeUInt32LE(0x01020304, 4);
console.log(b.toString('hex'));
console.log(b.readUInt32BE(0).toString(16));
const joined = Buffer.concat([Buffer.from('foo'), Buffer.from('bar')]);
console.log(joined.toString());Output
deadbeef04030201
deadbeef
foobarslice 共享内存
JavaScript
const a = Buffer.from('abcdef');
const s = a.subarray(0, 3); // 或 slice,效果一样
s[0] = 0x41; // 'A'
console.log(a.toString()); // 原 Buffer 被改了Output
Abcdefsubarray / slice 不复制,返回的是原 Buffer 的视图。想独立副本用 Buffer.from(a.subarray(0, 3))。处理网络包时这个细节会导致「改了切片,原数据也变了」的诡异 bug。大文件不要一次读完
Buffer 有长度上限(64 位平台约 4GB,buffer.constants.MAX_LENGTH)。读几百 MB 的日志、上传大文件,必须用 Stream 分块处理,见下一章。