参考:

深入浅出nodejs

1.基本

1.1 概念

Buffer是node自带,挂载全局对象global上,且无需引入
JavaScript 和 c++相结合
主要用来处理网络协议、操作数据库、处理图片、读写文件等需要处理大量二进制数据的场景。
既主要用来操作字节。

1.2 构成

Buffer对象类似于数组,元素为16进制的两位数(0-255,既1个字节byte(8bit)8位二进制包含的范围,2=256个数字)

  1. // v10后,new Buffer 由 Buffer.from代替
  2. let str0 = "窗"
  3. let buf6 = Buffer.from(str0, 'utf-8')
  4. console.log(buf6);
  5. let str1 = "a"
  6. let buf7 = Buffer.from(str1, 'utf-8')
  7. console.log(buf7);
  8. let str2 = "窗a"
  9. let buf8 = Buffer.from(str2, 'utf-8')
  10. console.log(buf8);

image.png
不同编码的字符串占用的元素个数不同,在UTF-8中,中文占用3个字符(3字节),字母和标点符合占用一个元素(一个字节)
不同编码参考:
语雀内容

  1. const buf = Buffer.from("1")
  2. console.log(buf);
  3. console.log(buf[0])
  4. const buf2 = Buffer.from("Hi")
  5. console.log(buf2);
  6. console.log(buf2[0])
  7. console.log(buf2[1])
  8. const buf3 = Buffer.from(" ")
  9. console.log(buf3);
  10. console.log(buf3[0])
  11. const buf4 = Buffer.from("ā")
  12. console.log(buf4);
  13. console.log(buf4[0], buf4[1])

image.png
参考Unicode码
image.png
字符 空格
image.png
字符 H 和 i
image.png
image.png
字符 1
image.png
拉丁字母 ā
image.png
16进制 二进制 之和
c4 81 101 ~~
196 129 257~~

2 内存分配

Buffer对象内存不在v8,而是在node的c++层面申请的。
Node在内存的使用上应用的是在C++层面申请内存、在JavaScript中分配内存的策略
Node采用了slab,分配机制slab就是一块申请好的固定大小的内存区域

当我们需要一个Buffer对象,可以通过以下方式分配指定大小的Buffer对象:
new Buffer(size);
Node以8 KB为界限来区分Buffer是大对象还是小对象:
Buffer.poolSize = 8 * 1024;
这个8 KB的值也就是每个slab的大小值
image.png
总之,
当分配小对象时,优先共用同一个空间够用的slab,容不下时,再创建新的slab
当分配大对象是,则直接分配一个slab空间,单独占用

3 与字符串互转

支持的编码类型
ASCII
UTF-8
UTF-16LE/UCS-2
Base64
Binary
Hex

3.1 字符串转Buffer

image.png
默认编码格式是UTF-8
不同编码格式,Buffer元素不同
image.png

3.2 Buffer转字符串

实现Buffer向字符串的转换也十分简单,Buffer对象的toString()可以将Buffer对象转换为字符串,
代码如下:
buf.toString([encoding], [start], [end])
比较精巧的是,可以设置encoding(默认为UTF-8)、start、end这3个参数实现整体或局部的转换。如果Buffer对象由多种编码写入,就需要在局部指定不同的编码,才能转换回正常的编码

3.3 字符串拼接-乱码问题

对于宽字节,比如中文字符,在UTF-8中占用三个字节,那么在Buffer常见的场景Strem中,总是一段一段buffer读取,就会涉及到拼接等问题,很容易出现乱码的问题,具体参考《深入浅出nodejs》

4 性能

网络传输中数据是二进制,所以预先把String转换成Buffer,会明显提高QPS
在Strem中,合理的设置highWaterMark也会提高文件读取速度