nodejs中的buffer

Buffer

Buffer 是什么?首先我们说说 JavaScriptJavaScript 刚开始并没有处理二进制数据的能力,因为最初时候并没有处理视频、音频、在线绘画等的业务场景,但是随着互联网发展,简单的文字图片展示功能已经不能满足用户的业务需求,音视频等二进制数据一直由 flash 代为处理,直到 nodejs 出现了让 JavaScript 第一次能够处理二进制数据的能力————Buffer,server 端的 JavaScript 有了处理二进制数据的能力,但是 client 端依旧无法处理二进制数据,直到 ES2015(es6)中, 才出现了处理二进制数据能力的对象 TypedArray,那 TypedArrayBuffer 又有什么关系呢?

Node 中的 Buffer 类是以更优化和更适合 Nodejs 的方式实现了 Unit8Array API,意思就是 Buffer 类其实是 TypedArray(Unit8Array)的 nodejs 实现。还是不明白?别急,我们先说说 TypedArray:
TypedArray 其实是将一个底层的二进制数据缓冲区描述成一个类似数组的视图的一个东西,这个东西以指定的格式解读二进制数据。它包含九种类型:

名称 描述
Int8Array 8 位有符号整数
Uint8Array 8 位无符号整数
Uint8ClampedArray 8 位无符号整型固定数组(数值在 0~255 之间)
Int16Array 16 位有符号整数
Uint16Array 16 位无符号整数
Int32Array 32 位有符号整数
Uint32Array 32 位无符号整数
Float32Array 32 位 IEEE 浮点数
Float64Array 64 位 IEEE 浮点数

Buffer就是TypedArrayUint8Array格式来解读二进制数据的 nodejs 的实现。

  • Buffer类似与从 0 到 255 之间的整数数组,如果不在这个范围会通过&255强制转到这个范围,例如: -100 就转成 156
  • Buffer的大小在创建时确定,且无法更改。
  • Buffer对象的内存分配不是在 V8 的堆内存中,而是在 Node 的 C++层面实现内存的申请
  • Buffer是缓冲器,注意是“缓冲”,而不是“缓存”,缓冲是为了解决速度慢和快的交接问题;速度快的需要通过缓冲区将数据一点一点传给速度慢的区域,例如内存到磁盘。而缓存是速度慢的设备需要通过缓存将经常要用到的数据缓存起来,缓存下来的数据可以提供高速的传输速度给速度快的设备,是为了重复使用。

Buffer 与字符编码

当字符串数据被存储入 Buffer 实例或从 Buffer 实例中被提取时,可以指定一个字符编码。Buffer中的数据很单纯,就是 0-255 的数据,它本身是不带编码的,编码是Buffer更上层的数据的规则,比如:

1
2
3
4
5
6
console.log(Buffer.from('hello world', 'ascii'));
console.log(Buffer.from('hello world', 'utf16le'));

// 打印出来
<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
<Buffer 68 00 65 00 6c 00 6c 00 6f 00 20 00 77 00 6f 00 72 00 6c 00 64 00>

同一个字符串使用不同编码传入Buffer后,在Buffer中的数据是不一样的

1
2
3
4
5
6
7
const myBuf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
console.log(myBuf.toString('ascii'));
console.log(myBuf.toString('hex'));

// 打印出来
buffer
627566666572

同一个Buffer,使用不同编码转成字符串也是不一样的

所以编码其实是写入或输出时对数据进行处理的标准,Buffer自带方法可以运用这些标准对要输入和准备输出的数据进行处理,但是内部数据和这些标准完全没关系。其实就是Buffer里面的数据是给计算机看的,而编码是为了将给计算机看的数据转变成人可以看懂的数据而定义的一套标准,在传入Buffer之前需要把人能看懂的数据转成机器能看懂的,而在传出Buffer之前需要把机器能看懂的数据转成人能看懂的。

Node.js 当前(10.16.3)支持的字符编码有:

  • ‘ascii’ - 仅适用于 7 位 ASCII 数据。此编码速度很快,如果设置则会剥离高位。

  • ‘utf8’ - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8。

  • ‘utf16le’ - 2 或 4 个字节,小端序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。

  • ‘ucs2’ - ‘utf16le’ 的别名。

  • ‘base64’ - Base64 编码。当从字符串创建 Buffer 时,此编码也会正确地接受 RFC 4648 第 5 节中指定的 “URL 和文件名安全字母”。

  • ‘latin1’ - 一种将 Buffer 编码成单字节编码字符串的方法(由 RFC 1345 中的 IANA 定义,第 63 页,作为 Latin-1 的补充块和 C0/C1 控制码)。

  • ‘binary’ - ‘latin1’ 的别名。

  • ‘hex’ - 将每个字节编码成两个十六进制的字符。