Node.js Buffer缓冲区完全指南
什么是Buffer?
Buffer是Node.js中用于处理二进制数据的核心模块。简单说,它就像一个固定大小的内存盒子,专门用来存放字节(bytes)。在JavaScript中,我们习惯处理字符串,但很多场景(比如读取图片、处理网络数据)需要直接操作二进制数据,这时候Buffer就派上用场了。
为什么需要Buffer?
JavaScript原本没有二进制数据的概念,它只认识字符串。但在Node.js中,我们要处理:
- 文件读写(图片、视频、PDF)
- 网络传输(TCP流、HTTP请求体)
- 加密解密
- 压缩解压 这些都涉及到二进制数据。如果用字符串处理,不仅效率低,还可能出现编码问题。
// 字符串处理二进制的问题示例
const str = "你好世界";
console.log(str.length); // 4 个字符
// 用Buffer看看真实的字节数
const buf = Buffer.from(str);
console.log(buf.length); // 12 个字节(UTF-8每个中文3字节)
创建Buffer
1. Buffer.alloc() - 创建指定大小的Buffer
// 创建一个10字节的Buffer,每个字节初始化为0
const buf1 = Buffer.alloc(10);
console.log(buf1); // <Buffer 00 00 00 00 00 00 00 00 00 00>
// 创建一个5字节的Buffer,每个字节初始化为1
const buf2 = Buffer.alloc(5, 1);
console.log(buf2); // <Buffer 01 01 01 01 01>
2. Buffer.allocUnsafe() - 快速创建(可能包含旧数据)
// 更快,但内容不确定(可能包含内存中的旧数据)
const buf3 = Buffer.allocUnsafe(10);
console.log(buf3); // 可能输出:<Buffer a0 b3 12 ...>
// 适用场景:你马上要填充数据,不需要初始化
3. Buffer.from() - 从现有数据创建
// 从字符串创建
const buf4 = Buffer.from("Hello");
console.log(buf4); // <Buffer 48 65 6c 6c 6f>
// 从数组创建
const buf5 = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
console.log(buf5.toString()); // Hello
// 从另一个Buffer创建
const buf6 = Buffer.from(buf4);
Buffer的读写操作
写入数据
const buf = Buffer.alloc(10);
// write方法返回实际写入的字节数
const written = buf.write("Hello", "utf8");
console.log(`写入了 ${written} 字节`); // 写入了 5 字节
// 可以指定起始位置
buf.write("World", 5);
console.log(buf.toString()); // HelloWorld
读取数据
const buf = Buffer.from("Hello World");
// 读取单个字节(0-255)
console.log(buf[0]); // 72 (H的ASCII码)
// 转换为字符串
console.log(buf.toString()); // Hello World
console.log(buf.toString("utf8", 0, 5)); // Hello
// 转换为JSON
console.log(buf.toJSON()); // { type: 'Buffer', data: [72, 101, 108, 108, 111, ...] }
Buffer与编码
常见的编码方式:
| 编码 | 说明 |
|---|---|
| utf8 | 默认编码,Unicode字符集 |
| ascii | 7位ASCII字符 |
| base64 | Base64编码,常用于网络传输 |
| hex | 十六进制表示 |
| binary | 二进制字符串 |
// Base64编码示例
const original = "Hello, 你好";
const buf = Buffer.from(original);
const base64 = buf.toString("base64");
console.log(base64); // SGVsbG8sIOS9oOWlvQ==
// 解码
const decoded = Buffer.from(base64, "base64").toString("utf8");
console.log(decoded); // Hello, 你好
实战场景
1. 读取图片文件
const fs = require("fs");
// 读取图片为Buffer
const imageBuffer = fs.readFileSync("photo.jpg");
console.log(`图片大小: ${imageBuffer.length} 字节`);
// 检查是否是JPEG格式(JPEG以FF D8开头,以FF D9结尾)
const isJpeg = imageBuffer[0] === 0xff && imageBuffer[1] === 0xd8;
console.log(`是JPEG格式: ${isJpeg}`);
2. 网络数据传输
const net = require("net");
const server = net.createServer((socket) => {
// 接收数据Buffer
socket.on("data", (data) => {
console.log("收到数据:", data.length, "字节");
console.log("内容:", data.toString());
// 发送Buffer数据
socket.write(Buffer.from("收到你的消息了"));
});
});
server.listen(3000, () => console.log("服务器启动在3000端口"));
3. 合并Buffer
// 多个Buffer合并成一个
const buf1 = Buffer.from("Hello ");
const buf2 = Buffer.from("World");
const combined = Buffer.concat([buf1, buf2]);
console.log(combined.toString()); // Hello World
// 指定合并后的总长度
const buf3 = Buffer.from("A");
const buf4 = Buffer.from("B");
const result = Buffer.concat([buf3, buf4], 10);
console.log(result.length); // 10
4. Buffer切片
const buf = Buffer.from("Hello World");
// slice不复制内存,只是创建视图
const slice = buf.slice(0, 5);
console.log(slice.toString()); // Hello
// 修改slice会影响原Buffer
slice.write("Hi");
console.log(buf.toString()); // Hi lo World
Buffer性能优化技巧
1. 复用Buffer池
// 不好的做法:频繁创建
for (let i = 0; i < 1000; i++) {
const buf = Buffer.alloc(1024);
// ...处理数据
}
// 好的做法:复用
const buf = Buffer.alloc(1024);
for (let i = 0; i < 1000; i++) {
buf.fill(0); // 清空
// ...处理数据
}
2. 使用allocUnsafe时立即填充
// 安全的做法
const buf = Buffer.allocUnsafe(100);
buf.fill(0); // 立即清零
常见问题
Buffer的最大大小
// 32位系统:约1GB
// 64位系统:约2GB
const maxBuf = Buffer.constants.MAX_LENGTH;
console.log(`Buffer最大大小: ${maxBuf / 1024 / 1024 / 1024} GB`);
中文编码问题
// GBK编码需要iconv-lite库
const iconv = require("iconv-lite");
const gbkBuffer = fs.readFileSync("gbk.txt");
const text = iconv.decode(gbkBuffer, "gbk");
小结
- Buffer是Node.js处理二进制数据的基础
- 创建Buffer:alloc(安全)、allocUnsafe(快速)、from(转换)
- 读写操作简单直观,支持多种编码
- 实际应用中注意性能优化和编码问题