在 Node.js 中,Buffer 类用于直接处理二进制数据。由于 JavaScript 最初设计用于处理字符串而非二进制数据,因此在 Node.js 中引入了 Buffer 来满足文件 I/O、网络通信等场景的需求。Buffer 在全局作用域内可用,无需 require()。本章将深入讲解 Buffer 的创建、操作、编码转换及最佳实践。
Buffer 是 Uint8Array 的子类,用于表示固定长度的字节序列。它专门用于在 Node.js 环境中处理二进制数据,例如从文件读取的内容、网络包等。Buffer 的大小在创建时就确定,且无法调整。
在引入 Buffer 之前,Node.js 通过字符串处理二进制数据,效率低下且容易出错。Buffer 提供了高效的内存分配和操作方式,直接与 V8 堆内存交互。
Node.js 提供了多种创建 Buffer 的方式。推荐使用 Buffer.alloc()、Buffer.from() 等方法,避免使用 new Buffer() 构造函数(已弃用)。
创建一个指定大小的 Buffer,默认填充为 0。可以指定填充内容和编码。
const buf1 = Buffer.alloc(10); // 长度为 10 的零填充缓冲区
console.log(buf1); //
const buf2 = Buffer.alloc(5, 'a'); // 用 'a' 的 ASCII 填充
console.log(buf2); //
创建一个指定大小的 Buffer,但不会初始化内存,因此速度更快,但可能包含旧数据(敏感信息)。使用后应立即填充数据,或仅用于后续写入。
const buf3 = Buffer.allocUnsafe(10);
console.log(buf3); // 可能包含随机数据
buf3.fill(0); // 立即覆盖
allocUnsafe 可能泄露内存中的敏感数据,除非确定会立即覆盖所有字节,否则应使用 alloc。
从现有数据创建 Buffer。支持多种参数类型:
// 从字符串创建(可指定编码,默认 utf8)
const buf4 = Buffer.from('Hello Node.js', 'utf8');
console.log(buf4); //
// 从数组创建(数组元素为字节值)
const buf5 = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
console.log(buf5.toString()); // 'Hello'
// 从 Buffer 复制(新 Buffer 共享原 Buffer 的内存?不,是副本)
const buf6 = Buffer.from(buf4);
console.log(buf6.equals(buf4)); // true,但它们是独立的
buf.write(string[, offset[, length]][, encoding]) 将字符串写入 Buffer 的指定位置。
const buf = Buffer.alloc(20);
const bytesWritten = buf.write('Hello', 0, 'utf8');
console.log('写入字节数:', bytesWritten); // 5
console.log(buf.toString('utf8', 0, bytesWritten)); // 'Hello'
const buf = Buffer.from('Node.js 教程', 'utf8');
console.log(buf.toString('utf8')); // 'Node.js 教程'
console.log(buf.toString('hex')); // 十六进制表示
console.log(buf.toJSON()); // { type: 'Buffer', data: [ 78, 111, 100, ... ] }
可以通过数组下标方式读写指定索引的字节(0-255)。
const buf = Buffer.alloc(5);
buf[0] = 72; // 'H'
buf[1] = 101; // 'e'
buf[2] = 108; // 'l'
buf[3] = 108; // 'l'
buf[4] = 111; // 'o'
console.log(buf.toString()); // 'Hello'
console.log(buf[0]); // 72
const buf = Buffer.from('Hello');
console.log(buf.length); // 5(字节数,不是字符数)
将多个 Buffer 拼接成一个新 Buffer。
const buf1 = Buffer.from('Hello ');
const buf2 = Buffer.from('World');
const buf3 = Buffer.concat([buf1, buf2]);
console.log(buf3.toString()); // 'Hello World'
比较两个 Buffer 的内容。常用于排序。
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('ABD');
console.log(buf1.compare(buf2)); // -1(表示 buf1 < buf2)
判断两个 Buffer 内容是否完全相同。
const buf1 = Buffer.from('Hello');
const buf2 = Buffer.from('Hello');
const buf3 = Buffer.from('World');
console.log(buf1.equals(buf2)); // true
console.log(buf1.equals(buf3)); // false
将一个 Buffer 的内容复制到另一个 Buffer。
const buf1 = Buffer.from('Hello World');
const buf2 = Buffer.alloc(5);
buf1.copy(buf2, 0, 0, 5);
console.log(buf2.toString()); // 'Hello'
返回一个新的 Buffer,与原 Buffer 共享内存(即修改会影响原 Buffer)。
const buf1 = Buffer.from('Hello World');
const buf2 = buf1.slice(0, 5);
buf2[0] = 72; // 改为 'H' 实际上没变,因为本来就是 'H'
buf2[1] = 97; // 改为 'a'
console.log(buf1.toString()); // 'Hallo World'(因为共享内存)
查找指定值在 Buffer 中第一次出现的位置。
const buf = Buffer.from('Hello World');
console.log(buf.indexOf('World')); // 6
Buffer 支持多种字符编码,常用的有:
'utf8':多字节编码,支持所有 Unicode 字符。'ascii':7 位 ASCII 编码。'hex':将每个字节编码为两个十六进制字符。'base64':Base64 编码。'latin1' 或 'binary':一种将 Buffer 编码成单字节字符串的方式。const buf = Buffer.from('Hello', 'utf8');
console.log(buf.toString('hex')); // 48656c6c6f
console.log(buf.toString('base64')); // SGVsbG8=
Buffer 实例的 toJSON() 返回一个包含类型和数据的对象,在 JSON 序列化时自动调用。
const buf = Buffer.from('Hello');
const json = JSON.stringify(buf);
console.log(json); // {"type":"Buffer","data":[72,101,108,108,111]}
// 还原
const parsed = JSON.parse(json);
const newBuf = Buffer.from(parsed.data);
console.log(newBuf.toString()); // 'Hello'
Buffer 是 Uint8Array 的子类,因此可以与其他 TypedArray 和 DataView 互操作。但需要注意,Buffer 分配的内存不在 V8 堆中,而 TypedArray 分配在堆内。
const buf = Buffer.from([1, 2, 3, 4]);
const uint8 = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
console.log(uint8[0]); // 1
const fs = require('fs');
fs.readFile('image.png', (err, data) => {
if (err) throw err;
// data 是一个 Buffer
console.log('PNG 文件头:', data.slice(0, 8).toString('hex'));
});
const http = require('http');
const server = http.createServer((req, res) => {
const buf = Buffer.from('Hello World');
const base64 = buf.toString('base64');
res.end(base64);
});
server.listen(3000);
// 假设有一个 24-bit RGB 图像数据,我们想把所有红色分量设为 0
function removeRed(buffer) {
for (let i = 0; i < buffer.length; i += 3) {
buffer[i] = 0; // 红色字节(假设顺序为 RGB)
}
return buffer;
}
Buffer.allocUnsafe() 比 alloc 快,但要注意安全性。slice 返回的 Buffer 与原 Buffer 共享内存,修改会影响原 Buffer。Buffer.from() 和 Buffer.alloc() 创建 Buffer。Buffer 是 Node.js 处理二进制数据的基石。本章介绍了 Buffer 的创建、读写、编码转换、常用方法及实际应用场景。熟练掌握 Buffer 对于深入使用 Node.js 进行文件操作、网络通信、加密解密等至关重要。下一章我们将探讨 zlib 模块,学习如何使用 Buffer 进行数据压缩与解压。