Node.js入门教程(十七):Buffer(缓冲区)

一、什么是 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
utf16le2 或 4 个字节,小字节序编码的 Unicode 字符
ucs2utf16le 的别名
base64Base64 编码
latin1一种把 Buffer 编码成一字节编码的字符串方式
binarylatin1 的别名
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 对象

返回值

返回一个数字,表示bufotherBuffer之前、之后或相同。

示例

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

返回值

返回一个新的缓冲区,它和旧缓冲区指向同一块内存,但是从索引startend的位置剪切。

示例

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 常用方法参考

序号方法 & 描述
1Buffer.from()- 从字符串、数组或 Buffer 创建 Buffer(推荐)
2buf.length- 返回 buffer 的字节数
3buf.write(string[, offset[, length]][, encoding])- 写入数据到 buffer
4buf.toString([encoding[, start[, end]]])- 从 buffer 读取数据
5buf.toJSON()- 将 Buffer 实例转换为 JSON 对象
6buf.equals(otherBuffer)- 比较两个缓冲区是否相等
7buf.compare(otherBuffer)- 比较两个 Buffer 对象
8buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])- 拷贝缓冲区
9buf.slice([start[, end]])- 裁剪缓冲区(共享内存)
10Buffer.concat(list[, totalLength])- 合并缓冲区
11buf.fill(value[, offset][, end])- 用指定值填充缓冲区
12buf.readUInt8(offset[, noAssert])- 读取无符号 8 位整数
13buf.readUInt16LE(offset[, noAssert])- 读取无符号 16 位整数(小端)
14buf.readUInt16BE(offset[, noAssert])- 读取无符号 16 位整数(大端)
15buf.readUInt32LE(offset[, noAssert])- 读取无符号 32 位整数(小端)
16buf.readUInt32BE(offset[, noAssert])- 读取无符号 32 位整数(大端)
17buf.readInt8(offset[, noAssert])- 读取有符号 8 位整数
18buf.readInt16LE(offset[, noAssert])- 读取有符号 16 位整数(小端)
19buf.readInt16BE(offset[, noAssert])- 读取有符号 16 位整数(大端)
20buf.readInt32LE(offset[, noAssert])- 读取有符号 32 位整数(小端)
21buf.readInt32BE(offset[, noAssert])- 读取有符号 32 位整数(大端)
22buf.readFloatLE(offset[, noAssert])- 读取 32 位浮点数(小端)
23buf.readFloatBE(offset[, noAssert])- 读取 32 位浮点数(大端)
24buf.readDoubleLE(offset[, noAssert])- 读取 64 位双精度数(小端)
25buf.readDoubleBE(offset[, noAssert])- 读取 64 位双精度数(大端)
26buf.writeUInt8(value, offset[, noAssert])- 写入无符号 8 位整数
27buf.writeUInt16LE(value, offset[, noAssert])- 写入无符号 16 位整数(小端)
28buf.writeUInt16BE(value, offset[, noAssert])- 写入无符号 16 位整数(大端)
29buf.writeUInt32LE(value, offset[, noAssert])- 写入无符号 32 位整数(小端)
30buf.writeUInt32BE(value, offset[, noAssert])- 写入无符号 32 位整数(大端)
31buf.writeInt8(value, offset[, noAssert])- 写入有符号 8 位整数
32buf.writeInt16LE(value, offset[, noAssert])- 写入有符号 16 位整数(小端)
33buf.writeInt16BE(value, offset[, noAssert])- 写入有符号 16 位整数(大端)
34buf.writeInt32LE(value, offset[, noAssert])- 写入有符号 32 位整数(小端)
35buf.writeInt32BE(value, offset[, noAssert])- 写入有符号 32 位整数(大端)
36buf.writeFloatLE(value, offset[, noAssert])- 写入 32 位浮点数(小端)
37buf.writeFloatBE(value, offset[, noAssert])- 写入 32 位浮点数(大端)
38buf.writeDoubleLE(value, offset[, noAssert])- 写入 64 位双精度数(小端)
39buf.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()以确保安全。