本文主要介绍在 NodeJS 中 Buffer 的使用,其中包括 Buffer 的创建、常用读写操作,以及 Buffer 操作中数据溢出的问题记录。
一、Buffer 介绍
Buffer,即缓冲区,是一个类似 Array 数组的对象,用于表示固定长度的字节序列。
Buffer 其本质是一块指定大小的内存空间,用于处理二进制数据。
Buffer 有以下特点:
- Buffer 大小固定,无法调整
- Buffer 性能高,可以对内存直接操作
- Buffer 中的每个元素就是 1 byte
二、Buffer 创建
Buffer 创建有三种方式:
Buffer.alloc()Buffer.allocUnsafe()Buffer.from()
Buffer.alloc()
通过Buffer.alloc()方法开辟指定字节大小的内存空间。
下面的示例中开辟了一块 10 字节的内存空间。
// alloc 开辟内存空间,10 bytes
let buf = Buffer.alloc(10);
console.log(buf);
使用alloc()会将新开辟内存中的数据写0,因此这里打印输出都是 0。
<Buffer 00 00 00 00 00 00 00 00 00 00>
Buffer.allocUnsafe()
通过Buffer.allocUnsafe()方法开辟指定字节大小的内存空间,这种方式会保留或复用旧的内存数据。
// alloc 开辟内存空间,10 bytes
// unsafe,会保留或复用先前的内存数据
let buf = Buffer.allocUnsafe(10);
通过Buffer.allocUnsafe(1000)使用 1000 bytes 的内存空间时有可能会看到打印的 Buffer 残留了一些数据。
这是因为内存本身是可以复用的,只不过在使用内存时allocUnsafe()方法并不会对内存中的数据写0,所以会看到它保留了旧的内存数据。
同时也因为allocUnsafe()方法没有写0操作,所以执行速度会快些。
let buf = Buffer.allocUnsafe(1000);
Buffer.from()
通过Buffer.from()方法可以将字符串或数组对象转为 Buffer。
// 根据字符串数据获取 Buffer 内容
let buf = Buffer.from('hello');
console.log(buf);
通过Buffer.from()方法将数组对象转为 Buffer。
// 根据数组数据获取 Buffer 内容
let buf = Buffer.from([105, 108, 111, 118]);
console.log(buf);
在字符串转换 Buffer 时,会将每一个字符根据在 Unicode 码表中对应的数字存储起来。
例如h这个字符在Unicode 码表中对应的数字是104,对应的十六进制为68。
因此Buffer.from('hello')在控制台查看 Buffer 输出时显示的十六进制数据表示如下。
<Buffer 68 65 6c 6c 6f>
三、Buffer操作
Buffer 与字符串的转换
前面讲可以通过Buffer.from()方法将字符串转为 Buffer,而Buffer.toString()方法可以将 Buffer 转为字符串。
在使用Buffer.toString()转为字符串时默认使用utf-8编码。
// Buffer.toString() 内容转字符,默认使用 utf-8 解码
let buf = Buffer.from('hello');
console.log(buf.toString()); // hello
Buffer 元素读写
Buffer 可以直接通过数字下标的形式对数据进行处理。
- 通过
buf[]读取下标数据。 - 通过
buf[].toString(2)可以进一步读取二进制数据。 - 通过给
buf[]赋值可以修改 Buffer 元素数据。
let buf = Buffer.from('hello');
console.log(buf[0]); // 104
console.log(buf[0].toString(2)); // 1101000
buf[0] = 95;
console.log(buf); // <Buffer 5f 65 6c 6c 6f>
console.log(buf.toString()); // _ello
四、Buffer 数据溢出
在给 Buffer 元素写数据时有可能造成溢出问题,在 Buffer 元素修改的值超过255时,那么超过 8 位的二进制数据会被丢弃。
例如下面的例子中给buf[0]赋值361,最终结果却是十六进制69。
- 首先由于一个字节由 8 位二进制数据表示,十进制
361转二进制为0001 0110 1001。 - 由于
361占 2 个字节,因此会舍弃高位二进制数据,也就是只保留0110 1001。 - 二进制
0110 1001的十六进制为69。
let buf = Buffer.from('hello');
buf[0] = 361;
console.log(buf);
<Buffer 69 65 6c 6c 6f>