乐趣区

必知必会之Buffer

笔者在最近的一两个月的开发中,一直在频繁的使用 Buffer,故将工作中常使用方式总结出来,以供大家参考和查阅,也可作为自己的备忘录。

创建

Buffer.alloc: 当已知 buffer 的长度的时候可以使用 Buffer.alloc 进行创建,其接收三个参数:

  • length,buffer 的长度
  • fill, 默认填充值
  • encoding, 如果 fill 是个字符串,可以指定字符串的编码
let buf = Buffer.alloc(3);

Buffer.allocUnsafe: 内存内容未初始化,可能包含敏感信息,需要使用 Buffer.fill 进行初始化

let buf = Buffer.allocUnsafe(3);
buf.fill(0)

Buffer.from: 当需要根据内容创建 buffer 的时候使用该函数,参数可以为 字符串 buffer 数据 整数数组,具体如下:

let buf = Buffer.from("abc");
console.log(buf);

let buf2 = Buffer.from([0x61, 0x62, 0x63]);
console.log(buf2);

let buf3 = Buffer.from(buf);
console.log(buf3);

注意在给 from 传参数的时候一定要确实是以上类型,不然可以会抛出异常:

First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object

写入

笔者在工作中较常写入的是数字,就以整数为例,其他类似,比如需要写入数据的 T(type)、L(length)

buf.writeInt8: 给 buffer 中写入整数数据,包含两个参数:value(写入的值) 和 offset(写入的起点)

buf.writeInt8(101, 0);

writeInt16BE: 写入大端 2 个字节数据,大端表示高位在前, 相对的 writeInt16LE 表示地位在前

let buf = Buffer.alloc(3);
buf.writeInt8(101, 0);
buf.writeInt16BE(200, 1);
console.log(buf);
// <Buffer 65 00 c8> 其中展示的数据均为 16 进制

注意指定的写入起点一定在 buffer 的长度范围之内,不然会出现RangeError: Index out of range, 如改写上面例子

buf.writeInt16BE(200, 2);

//RangeError: Index out of range
//    at checkInt (buffer.js:1178:11)
//    at Buffer.writeInt16BE (buffer.js:1355:5)
//

读取

Buffer.readInt8: 指定 buffer 开始读取位置,然后读取一位

let buf = Buffer.alloc(3);
buf.writeInt8(101, 0);
buf.writeInt16BE(200, 1);

console.log(buf.readInt8(0)); // 101

Buffer.readInt16BE: 与写入相对,读取也分为大小端,按照大端方式读取数据,并且读取两位

let buf = Buffer.alloc(3);
buf.writeInt8(101, 0);
buf.writeInt16BE(200, 1);

console.log(buf.readInt16BE(1)); // 200

拼接

Buffer.concat: 对于已有 buffer 数据进行拼接, 接收一个 buffer list 如:[buffer1, buffer2…]和拼接生成的 buffer 总长度,可不指定, 如一下拼接一个 TLV 数据,格式如下:

let buf = Buffer.alloc(3);
const length = 200;
const type = 101;
const value = Buffer.from("abc");
buf.writeInt8(type, 0); //type
buf.writeInt16BE(length, 1);
const result = Buffer.concat([buf, value]);

console.log(result); // <Buffer 65 00 c8 61 62 63>

转换

buffer.toString: 支持一下几种方式转换:

  • hex, 将二进制内容转为 16 进制
  • base64, 转为 base64 编码 // 数据传输中常用
  • ascii, ascii 编码
  • utf8,UTF- 8 编码
//result 为前面例子的结果
result.toString('base64'); // ZQDIYWJj

const buf1 = Buffer.allocUnsafe(26);

for (let i = 0; i < 26; i++) {
  // 97 is the decimal ASCII value for 'a'.
  buf1[i] = i + 97;
}

console.log(buf1.toString('ascii'));

笔者比较常用的是将 TLV 数据转为 base64 编码,具体原理可以查看 Base64 编码与解码详解

退出移动版