一、什么是 Buffer?
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。
Node.js 中的Buffer 类是用于处理二进制数据的核心工具,提供了对二进制数据的高效操作。
Buffer 类在处理文件操作、网络通信、图像处理等场景中特别有用。
Buffer 的特性
| 特性 | 说明 |
|---|---|
| 二进制数据 | Buffer 对象是一个包含原始二进制数据的固定大小的数组,每个元素占用一个字节(8位),适合处理文件内容、网络数据包等 |
| 固定长度 | Buffer 对象的内容可以在创建后修改,但其长度是固定的,不能动态改变 |
二、Buffer 与字符编码
Buffer 实例一般用于表示编码字符的序列,比如 UTF-8、UCS2、Base64 或十六进制编码的数据。通过使用显式的字符编码,就可以在 Buffer 实例与普通的 JavaScript 字符串之间进行相互转换。
const buf = Buffer.from('runoob', 'ascii'); // 输出 72756e6f6f62 console.log(buf.toString('hex')); // 输出 cnVub29i console.log(buf.toString('base64'));Node.js 支持的字符编码
| 编码 | 说明 |
|---|---|
| ascii | 仅支持 7 位 ASCII 数据,速度很快 |
| utf8 | 多字节编码的 Unicode 字符,许多网页和文档格式都使用 UTF-8 |
| utf16le | 2 或 4 个字节,小字节序编码的 Unicode 字符 |
| ucs2 | utf16le 的别名 |
| base64 | Base64 编码 |
| latin1 | 一种把 Buffer 编码成一字节编码的字符串方式 |
| binary | latin1 的别名 |
| hex | 将每个字节编码为两个十六进制字符 |
三、创建 Buffer
Buffer 提供了以下 API 来创建 Buffer 类:
| 方法 | 说明 |
|---|---|
Buffer.alloc(size[, fill[, encoding]]) | 创建长度为 size 字节的 Buffer,每个字节的值为 0(推荐) |
Buffer.allocUnsafe(size) | 创建长度为 size 字节的 Buffer,但可能包含旧数据(更快但不安全) |
Buffer.allocUnsafeSlow(size) | 分配给定大小的新 Buffer 实例,但不对其进行初始化 |
Buffer.from(array) | 返回一个被 array 的值初始化的新的 Buffer 实例 |
Buffer.from(arrayBuffer[, byteOffset[, length]]) | 返回与给定 ArrayBuffer 共享同一内存的 Buffer |
Buffer.from(buffer) | 复制传入的 Buffer 实例的数据,返回新的 Buffer 实例 |
Buffer.from(string[, encoding]) | 通过字符串创建 Buffer,可指定编码,默认为 UTF-8 |
创建示例
// 创建一个长度为 10、且用 0 填充的 Buffer const buf1 = Buffer.alloc(10); // 创建一个长度为 10、且用 0x1 填充的 Buffer const buf2 = Buffer.alloc(10, 1); // 创建一个长度为 10、且未初始化的 Buffer // 这个方法比 Buffer.alloc() 更快,但可能包含旧数据 const buf3 = Buffer.allocUnsafe(10); // 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer const buf4 = Buffer.from([1, 2, 3]); // 创建一个包含 UTF-8 字节的 Buffer const buf5 = Buffer.from('tést'); // 创建一个包含 Latin-1 字节的 Buffer const buf6 = Buffer.from('tést', 'latin1');四、写入缓冲区
语法
buf.write(string[, offset[, length]][, encoding])
参数
| 参数 | 说明 |
|---|---|
string | 写入缓冲区的字符串 |
offset | 缓冲区开始写入的索引值,默认为 0 |
length | 写入的字节数,默认为buffer.length |
encoding | 使用的编码,默认为 'utf8' |
返回值
返回实际写入的大小。如果 buffer 空间不足,则只会写入部分字符串。
示例
buf = Buffer.alloc(256); len = buf.write("www.runoob.com"); console.log("写入字节数 : " + len);执行以上代码,输出结果为:
$ node main.js 写入字节数 : 14
五、从缓冲区读取数据
语法
buf.toString([encoding[, start[, end]]])
参数
| 参数 | 说明 |
|---|---|
encoding | 使用的编码,默认为 'utf8' |
start | 指定开始读取的索引位置,默认为 0 |
end | 结束位置,默认为缓冲区的末尾 |
返回值
解码缓冲区数据并使用指定的编码返回字符串。
示例
buf = Buffer.alloc(26); for (var i = 0 ; i < 26 ; i++) { buf[i] = i + 97; } console.log(buf.toString('ascii')); // 输出: abcdefghijklmnopqrstuvwxyz console.log(buf.toString('ascii', 0, 5)); // 输出: abcde console.log(buf.toString('utf8', 0, 5)); // 输出: abcde console.log(buf.toString(undefined, 0, 5)); // 输出: abcde六、将 Buffer 转换为 JSON 对象
语法
buf.toJSON()
当字符串化一个 Buffer 实例时,JSON.stringify()会隐式地调用该toJSON()方法。
示例
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]); const json = JSON.stringify(buf); // 输出: {"type":"Buffer","data":[1,2,3,4,5]} console.log(json); const copy = JSON.parse(json, (key, value) => { return value && value.type === 'Buffer' ? Buffer.from(value.data) : value; }); // 输出: <Buffer 01 02 03 04 05> console.log(copy);七、缓冲区合并
语法
Buffer.concat(list[, totalLength])
参数
| 参数 | 说明 |
|---|---|
list | 用于合并的 Buffer 对象数组列表 |
totalLength | 指定合并后 Buffer 对象的总长度 |
返回值
返回一个多个成员合并的新 Buffer 对象。
示例
var buffer1 = Buffer.from('教程'); var buffer2 = Buffer.from('www.runoob.com'); var buffer3 = Buffer.concat([buffer1, buffer2]); console.log("buffer3 内容: " + buffer3.toString());执行以上代码,输出结果为:
buffer3 内容: 教程www.chenbyte.cn
八、缓冲区比较
语法
buf.compare(otherBuffer);
参数
| 参数 | 说明 |
|---|---|
otherBuffer | 与 buf 对象比较的另外一个 Buffer 对象 |
返回值
返回一个数字,表示buf在otherBuffer之前、之后或相同。
示例
var buffer1 = Buffer.from('ABC'); var buffer2 = Buffer.from('ABCD'); var result = buffer1.compare(buffer2); if (result < 0) { console.log(buffer1 + " 在 " + buffer2 + "之前"); } else if (result == 0) { console.log(buffer1 + " 与 " + buffer2 + "相同"); } else { console.log(buffer1 + " 在 " + buffer2 + "之后"); }执行以上代码,输出结果为:
ABC在ABCD之前
九、拷贝缓冲区
语法
buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
参数
| 参数 | 说明 |
|---|---|
targetBuffer | 要拷贝的 Buffer 对象 |
targetStart | 可选,默认: 0 |
sourceStart | 可选,默认: 0 |
sourceEnd | 可选,默认:buffer.length |
返回值
没有返回值。
示例
var buf1 = Buffer.from('abcdefghijkl'); var buf2 = Buffer.from('RUNOOB'); // 将 buf2 插入到 buf1 指定位置上 buf2.copy(buf1, 2); console.log(buf1.toString());执行以上代码,输出结果为:
abRUNOOBijkl
十、缓冲区裁剪
语法
buf.slice([start[, end]])
参数
| 参数 | 说明 |
|---|---|
start | 可选,默认: 0 |
end | 可选,默认:buffer.length |
返回值
返回一个新的缓冲区,它和旧缓冲区指向同一块内存,但是从索引start到end的位置剪切。
示例
var buffer1 = Buffer.from('runoob'); // 剪切缓冲区 var buffer2 = buffer1.slice(0, 2); console.log("buffer2 content: " + buffer2.toString());执行以上代码,输出结果为:
buffer2 content: ru
十一、缓冲区长度
语法
buf.length;
返回值
返回 Buffer 对象所占据的内存长度。
示例
var buffer = Buffer.from('www.runoob.com'); // 缓冲区长度 console.log("buffer length: " + buffer.length);执行以上代码,输出结果为:
buffer length: 14
十二、Buffer 常用方法参考
| 序号 | 方法 & 描述 |
|---|---|
| 1 | Buffer.from()- 从字符串、数组或 Buffer 创建 Buffer(推荐) |
| 2 | buf.length- 返回 buffer 的字节数 |
| 3 | buf.write(string[, offset[, length]][, encoding])- 写入数据到 buffer |
| 4 | buf.toString([encoding[, start[, end]]])- 从 buffer 读取数据 |
| 5 | buf.toJSON()- 将 Buffer 实例转换为 JSON 对象 |
| 6 | buf.equals(otherBuffer)- 比较两个缓冲区是否相等 |
| 7 | buf.compare(otherBuffer)- 比较两个 Buffer 对象 |
| 8 | buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])- 拷贝缓冲区 |
| 9 | buf.slice([start[, end]])- 裁剪缓冲区(共享内存) |
| 10 | Buffer.concat(list[, totalLength])- 合并缓冲区 |
| 11 | buf.fill(value[, offset][, end])- 用指定值填充缓冲区 |
| 12 | buf.readUInt8(offset[, noAssert])- 读取无符号 8 位整数 |
| 13 | buf.readUInt16LE(offset[, noAssert])- 读取无符号 16 位整数(小端) |
| 14 | buf.readUInt16BE(offset[, noAssert])- 读取无符号 16 位整数(大端) |
| 15 | buf.readUInt32LE(offset[, noAssert])- 读取无符号 32 位整数(小端) |
| 16 | buf.readUInt32BE(offset[, noAssert])- 读取无符号 32 位整数(大端) |
| 17 | buf.readInt8(offset[, noAssert])- 读取有符号 8 位整数 |
| 18 | buf.readInt16LE(offset[, noAssert])- 读取有符号 16 位整数(小端) |
| 19 | buf.readInt16BE(offset[, noAssert])- 读取有符号 16 位整数(大端) |
| 20 | buf.readInt32LE(offset[, noAssert])- 读取有符号 32 位整数(小端) |
| 21 | buf.readInt32BE(offset[, noAssert])- 读取有符号 32 位整数(大端) |
| 22 | buf.readFloatLE(offset[, noAssert])- 读取 32 位浮点数(小端) |
| 23 | buf.readFloatBE(offset[, noAssert])- 读取 32 位浮点数(大端) |
| 24 | buf.readDoubleLE(offset[, noAssert])- 读取 64 位双精度数(小端) |
| 25 | buf.readDoubleBE(offset[, noAssert])- 读取 64 位双精度数(大端) |
| 26 | buf.writeUInt8(value, offset[, noAssert])- 写入无符号 8 位整数 |
| 27 | buf.writeUInt16LE(value, offset[, noAssert])- 写入无符号 16 位整数(小端) |
| 28 | buf.writeUInt16BE(value, offset[, noAssert])- 写入无符号 16 位整数(大端) |
| 29 | buf.writeUInt32LE(value, offset[, noAssert])- 写入无符号 32 位整数(小端) |
| 30 | buf.writeUInt32BE(value, offset[, noAssert])- 写入无符号 32 位整数(大端) |
| 31 | buf.writeInt8(value, offset[, noAssert])- 写入有符号 8 位整数 |
| 32 | buf.writeInt16LE(value, offset[, noAssert])- 写入有符号 16 位整数(小端) |
| 33 | buf.writeInt16BE(value, offset[, noAssert])- 写入有符号 16 位整数(大端) |
| 34 | buf.writeInt32LE(value, offset[, noAssert])- 写入有符号 32 位整数(小端) |
| 35 | buf.writeInt32BE(value, offset[, noAssert])- 写入有符号 32 位整数(大端) |
| 36 | buf.writeFloatLE(value, offset[, noAssert])- 写入 32 位浮点数(小端) |
| 37 | buf.writeFloatBE(value, offset[, noAssert])- 写入 32 位浮点数(大端) |
| 38 | buf.writeDoubleLE(value, offset[, noAssert])- 写入 64 位双精度数(小端) |
| 39 | buf.writeDoubleBE(value, offset[, noAssert])- 写入 64 位双精度数(大端) |
十三、本章小结
| 知识点 | 说明 |
|---|---|
| Buffer 是什么 | Node.js 中处理二进制数据的核心工具 |
| 创建 Buffer | 推荐使用Buffer.from()、Buffer.alloc() |
| 写入数据 | buf.write()将字符串写入缓冲区 |
| 读取数据 | buf.toString()从缓冲区读取字符串 |
| 合并与复制 | Buffer.concat()合并,buf.copy()复制 |
| 裁剪 | buf.slice()裁剪(共享内存,注意修改影响原 Buffer) |
| 长度 | buf.length获取缓冲区字节数 |
| JSON 转换 | buf.toJSON()转换为 JSON 对象 |
| 编码支持 | UTF-8、ASCII、Base64、Hex 等多种编码 |
提示:
Buffer.allocUnsafe()虽然更快,但可能包含旧数据,使用前需要填充或覆盖。推荐在大多数场景下使用Buffer.alloc()或Buffer.from()以确保安全。