在ECMAScript 2015(ES6)推出TypeArray
标准之前,JavaScript语言处理二进制数据非常困难,这在后端开发中使用很不方便。Node.js中的Buffer
类就是为了解决二进制数据处理的问题,该类为Node.js带来了如TCP流操作和文件系统流操作的能力。ECMAScript 2015中TypeArray
做为语言标准被引入,使JavaScript可以原生处理二进制数据。那么,在Node.js开发中我们是应该使用Buffer
还是应该使用TypeArray
呢?
1. Buffer
类
Node.js是用于服务器端的语言,在服务器编程中二进制数据处理是必不可少的。Buffer
类是为解决JavaScript处理二进制数据处理的问题,该类做为一个全局对象提供。Node.js中用于TCP网络处理的net
模块、流处理模块stream
、文件处理模块fs
等都依赖于该模块进行底层的二进制数据处理。
Buffer
的使用非常简单灵活。
如,使用16进制的数组创建缓存:
const buf = new Buffer([0x62,0x75,0x66,0x66,0x65,0x72]); // 创建一个包含以下 ASCII 编码字符串的缓存 // ['b','u','f','f','e','r']
从另一个缓存中创建新缓存:
const buf1 = new Buffer('buffer'); const buf2 = new Buffer(buf1); buf1[0] = 0x61; console.log(buf1.toString()); // 'auffer' console.log(buf2.toString()); // 'buffer' (未修改)
也可以从TypedArray
的.buffer
属性或new ArrayBuffer()
创建:
const arr = new Uint16Array(2); arr[0] = 5000; arr[1] = 4000; const buf = new Buffer(arr.buffer); // 与arr共享内存; console.log(buf); // <Buffer 88 13 a0 0f> // TypdArray 修改后 Buffer 同样会修改 arr[1] = 6000; console.log(buf); // <Buffer 88 13 70 17>
也可以不添加内容,创建一个空数组:
const buf = new Buffer(5); console.log(buf); // <Buffer 78 e0 82 02 01< (每次值可能不一样)
使用字符串创建缓存时,可以指定字符编码;也可以通过toString()
进行字符编码的转换:
const buf1 = new Buffer('this is a tést'); console.log(buf1.toString()); // this is a tést console.log(buf1.toString('ascii')); // prints: this is a tC)st const buf2 = new Buffer('7468697320697320612074c3a97374', 'hex'); console.log(buf2.toString()); // prints: this is a tést
2. TypeArray
-类型数组
TypeArray
(类型数组)在ECMAScript 2015中被加到语言标准中,它赋予了JavaScript直接读写二进制数据能力。TypeArray
是一组类似数组的对象,它由ArrayBuffer
、TypedArray
、DataView
三类对象构成:
ArrayBuffer
是一个是一个用于表示二进制缓冲区(buffer)的对象,它并没有能力去访问和操作它自身的数据内容,要操作ArrayBuffer
中的数据,需要创建一个Typed Array View
或DataView
来读写缓存区内容。Typed Array View
即类型数组视图,是一组具有描述性的名字的不同类型的数组视图。如:Uint8Array
、Int8Array
、Int32Array
、Float32Array
等DataView
提供了一些底层的API,通过这些API可以从ArrayBuffer
中读/写数据。
ArrayBuffer
可以用于创建一个指定长度的二进制数组,但该对象并不能直接读写,需要借助Typed Array View
或DataView
读写其数据。
Typed Array View
是一组不同类型的数组视图,它不同于DataView
。DataView
只能用于ArrayBuffer
数据的读写,而不同类型的Typed Array View
除了可以读写ArrayBuffer
外,还可以单独使用。
如,创建一个ArrayBuffer
并使用Typed Array View
或DataView
读写数据:
var buffer = new ArrayBuffer(8); var int32 = new Int32Array(buffer); int32[0] = 42; console.log(int32[0]); // 42 // 使用 DataView 读写 var dv = new DataView(buffer, 0); dv.setInt16(1, 42); dv.getInt16(1);
TypedArray
也可以独立使用:
// 创建一个指定长度的 TypedArray var uint8 = new Uint8Array(2); uint8[0] = 42; console.log(uint8[0]); // 42
3. Buffer
与TypeArray
的比较
JavaScript已原生支持二进制数据处理,那么我们应该直接使用原生的TypeArray
还是应该使用Buffer
处理二进制数据,二者之间有什么区别呢?
Buffer
是对Uint8Array
的实现
Buffer
类实现了Uint8Array
相关API。但Node对Buffer
类进行了优化,其更适合在Node.js环境中使用。
Buffer
并不完全兼容类型数组
Buffer
同样是一个Uint8Array
类型数组实例。但它与ES6中的类型数组规范并不完全兼容,如:ArrayBuffer#slice()
会创建一个分隔部分数据的拷贝,而Buffer#slice()
会创建一个从Buffer
中拷贝数据的视图,相对来说Buffer#slice()
更高效。
Buffer
可以与类型数组共享内存区
可以从TypedArray
的.buffer
属性或new ArrayBuffer()
创建一个Buffer
对象。该对象会与类型数组共享内存区:
const arr = new Uint16Array(2); arr[0] = 5000; arr[1] = 4000; const buf1 = new Buffer(arr); // 复制 buffer const buf2 = new Buffer(arr.buffer); // 与 arr 共享内存空间 console.log(buf1); // <Buffer 88 a0>,仅复制了两个元素 console.log(buf2); // <Buffer 88 13 a0 0f>