Node.js Buffer缓冲区完全指南

什么是Buffer?

Buffer是Node.js中用于处理二进制数据的核心模块。简单说,它就像一个固定大小的内存盒子,专门用来存放字节(bytes)。在JavaScript中,我们习惯处理字符串,但很多场景(比如读取图片、处理网络数据)需要直接操作二进制数据,这时候Buffer就派上用场了。

为什么需要Buffer?

JavaScript原本没有二进制数据的概念,它只认识字符串。但在Node.js中,我们要处理:

// 字符串处理二进制的问题示例
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");

小结

  1. Buffer是Node.js处理二进制数据的基础
  2. 创建Buffer:alloc(安全)、allocUnsafe(快速)、from(转换)
  3. 读写操作简单直观,支持多种编码
  4. 实际应用中注意性能优化和编码问题