Node 中的 Buffer 对象

161 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

Node 中的 Buffer 对象

Buffer是 Node 特有(区别于浏览器JavaScript)的数据类型,主要用来处理二进制数据,在前端 JavaScript 中,和二进制数据打交道的机会比较少(ES20l5增加了ArrayBuffer类型,用来操作二进制数据流,Node 也可以使用该类型)。而Node在进行Web开发时经常需要和前端进行数据通信,二进制数据流十分常见(例如传输一张 gif 图片),因此 Node 除了String外,还内置了Buffer这一数据类型,它是Node作为运行时对JavaScript 做的扩展。

Buffer属于固有(built-in)类型,因此无须使用require进行引入。

在文件操作和网络操作中,如果不显式声明编码格式,其返回数据的默认类型就是 Buffer。例如下面读取文件的例子,如果不指定编码格式,得到的结果就是Buffer字符串。

// 读取一个文件并打印内容 
const fs = require("fs");
fs.readFile("foo.txt", (err, results) => {
  console.log(results);
  // <Buffer 48 65 6c6c 6f 20 57 6f 72 6c 64> (Hello Node)
});

上面的代码中,最后打印出的是十六进制的数据,由于纯二进制格式太长而且难以阅读,Buffer通常表现为十六进制的字符串。

1. Buffer 的构建与转换

可以使用Buffer类直接初始化一个Buffer对象,参数可以是由二进制数据组成的数组。

const buffer = new Buffer([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x4e, 0x6f, 0x64, 0x65]);
// Hello Node

如果想由字符串来得到一个Buffer,同样可以调用构造函数来实现,例如:

const buffer = new Buffer("Hello Node");
console.log(buffer); // <Buffer 48 65 6c6c 6f 20 4e 6f 64 65>

注意:在最新的Node API中,Buffer()方法被标记为Deprecated,表示已经不推荐使用,因为这个方法在某些情况下可能不安全(参考htps:/github.com/nodejs/node//issues/4660),并且会在将来的版本中将其移除。

目前推荐的是使用Buffer.from方法来初始化一个Buffer对象,上面的代码可以改写为如下形式。

// 使用 Buffer.from 来初始化一个 Buffer
const buffer = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x4e, 0x6f, 0x64, 0x65]);
// "Hello Node"
const buffer = Buffer.from("Hello Node");
console.log(buffer); // <Buffer 48 65 6c6c 6f 20 4e 6f 64 65>

如果想把一个Buffer对象转成字符串形式,需要使用toString方法,调用格式为:

buffer.tostring([encoding], [start], [end])
  • encoding:目标编码格式
  • start:开始位置
  • end:结束位置

Buffer支持的编码类型种类有限,只有以下6种:

  • ASCII
  • Base64
  • Binary
  • Hex
  • UTF-8
  • UTF-16LE/UCS-2

不过也已经覆盖了最常用的编码类型。Buffer还提供了isEncoding方法来判断是否支持转换为目标编码格式。

例如,如果我们想把上一节表示“Hello Node”Buffer对象转换为字符串,那么可以调用:

// 只转换前5个字符,输出 "He11o"
console.log(buffer.tostring("utf-8", 0 , 5));

如果toString在调用时不包含任何参数,那么就会默认采用 UTF-8 编码,并转换整个Buffer对象。

2. Buffer 的拼接

Buffer一个常见的使用场景是用来处理 HTTP 的post请求,随便在网络上搜索,都能看到类似如下的代码。

// 使用 += 来拼接 Buffer
let body = '';
req.setEncoding ('utf8');
req.on('data', function(chunk){
  body += chunk;
});
reg.on('end',function(){
  // do something
});

上面的代码使用 += 来拼接上传的数据流,这个过程包含了一个隐式的编码转换。

body += chunk相当于body += chunk.toString(),当上传字符全都是英文的时候固然没关系,但如果字符串中包含中文或者其他语言,由于toString方法默认使用utf-8编码,这时就有可能出现乱码。