Node.js的缓存类Buffer-Buffer类的创建、类方法

 2015年11月21日    1016     声明


Javascript 语言内部使用 Unicode 编码,其对 Unicode 编码支持较好,但确难以处理二进制数据。在网络编程中,如:处理 TCP 流和 fs 文件系统时,需要经常操作字节流。Node.js 提供了Buffer类,该类可以方便的操作、创建、以及处理字节流。

  1. 类: Buffer
  2. Buffer类的创建
  3. Buffer类方法
  4. 类:SlowBuffer
  5. 支持ES6 iterator迭代器


1. 类: Buffer

Buffer是一个全局对象,所以不需要require引用即可使用。

创见Buffer类实例后,类实例中会存储原始的二进制数据,Buffer类实例一旦创建后,其大小无法改变。Buffer的数据存储与数组类似,其数据存储位置位于 V8 堆之外的原始内存区域。

创建一个类似数组的Buffer,应该注意以下规则:

  1. Buffer 是内存拷贝,而不是内存共享。

  2. Buffer 占用内存可以理解为一个数组,但其实并不是字节数组。比如,new Uint32Array(new Buffer([1,2,3,4])) 创建了4个 Uint32Array,它的成员为 [1,2,3,4],而不是[0x1020304][0x4030201]


Buffer与字符串转换

Buffer类可以和JavaScript String对象之间进行转换。Buffer缓存数据转换为字符串时,需要提供一个编码方式。支持的编码方式有:

  • 'ascii' - 7位的 ASCII 数据。这种编码方式非常快,而且会剥离设置过高的bit。

  • 'utf8' - 多字节编码 Unicode 字符。大部分网页和文档使用这类编码方式。

  • 'utf16le' - 2个或4个字节,Little Endian (LE) 编码 Unicode 字符。编码范围 (U+10000 到 U+10FFFF) 。

  • 'ucs2' - 'utf16le'的别名。

  • 'base64' - Base64 字符串编码。

  • 'binary' - 将原始2进制数据编码为字符串。
  • 'hex' - 每个byte编码成2个十六进制字符。


2. Buffer类的创建

创建Buffer类可以使用其构造函数new Buffer(),该函数可以接受多种形式的参数:

new Buffer(size)

  • size Number 类型

创建一个其大小是size字节的buffer实例。size不能大于1,073,741,824 bytes (1 GB) (32位系统)或不能大于2,147,483,648 bytes (2 GB) (64位系统)。

new Buffer(array)

  • array Array

通过一个8字节数组创建buffer实例。

new Buffer(buffer)

  • buffer Buffer

拷贝一个buffer实例的数据到另一个buffer实例。

new Buffer(str[, encoding])

  • str String,需要存入缓存的字符串
  • encoding String,可选参数,表示字符串的编码方式

通过传入的str字符串创建buffer实例,传入字符串的默认编码方式是'utf8'


3. Buffer类方法

类方法指不需要实例化,通过类名就可以调用的方法。Buffer类中包含以下类方法:

Buffer.byteLength(string[, encoding])

  • string String 类型
  • encoding String 类型,可选参数,默认: 'utf8'
  • 返回值: Number 类型

返回这个字符串真实byte长度。 encoding 编码默认是: 'utf8'。这个方法不同与String.prototype.length,返回是byte长度而不是字符数。在写入HTTP响应头Cotent-Lengthk时,要使用Buffer.byteLength 方法判断内容长度,而不能使用String.prototype.length

Buffer.isEncoding(encoding)

  • encoding String 类型,表示编码方式的字符串
  • 返回值: Boolean

判断encoding是否是有效的编码方式,是则返回true,否则返回false

Buffer.isEncoding('hex');  //true
Buffer.isEncoding('utf16');  //false

Buffer.isBuffer(obj)

  • obj Object 类型
  • 返回值: Boolean

判断传入对象obj是否是一个Buffer

Buffer.concat(list[, totalLength])

  • list Array,被连接的Buffer数组
  • totalLength Number,数组对象里总Buffer大小

将数组中所有的buffer实例通过复制拼接在一起,返回值是一个新的Buffer实例。

如果传入的数组没有内容,或者totalLength参数是0,那将返回一个长度为0的buffer。如果数组中仅有一项,将返回第一项,如果多于一项将创建一个的buffer

Buffer.compare(buf1, buf2)

  • buf1 Buffer
  • buf2 Buffer

比较buf1是在buf2之前还是之后,与实例方法buf1.compare(buf2)类似。

var arr = [Buffer('1234'), Buffer('0123')];
arr.sort(Buffer.compare);


4. 类:SlowBuffer

该类可以创建一个不被池管理的Buffer

Node对缓存的管理机制:为了避免创建大量独立分配的Buffer带来的垃圾回收开销,默认情况下小于 4KB 的空间都是切割自一个较大的独立对象。这种策略既提高了性能也改善了内存使用,因为 V8 不需要跟踪和清理很多Persistent对象。

当开发者需要将池中一小块数据保留不确定的一段时间,较为妥当的办法是用SlowBuffer创建一个不被池管理的Buffer实例并将相应数据拷贝出来。

socket.on('readable', function() {
  var data = socket.read();
  // 为需要保留的数据分配内存
  var sb = new SlowBuffer(10);
  // 将数据拷贝到新的空间中
  data.copy(sb, 0, 0, 10);
  store.push(sb);
});


5. 支持ES6 iterator迭代器

Buffer是可迭代的,可以通过ES6中的for..of访问其中的数据:

var buf = new Buffer([1, 2, 3]);

for (var b of buf)
  console.log(b)

// 1
// 2
// 3