在ECMAScript 2015(ES6)中引入TypedArray
以前,JavaScript中没有读取或操做二进制数据流的机制。 Buffer
类做为Node.js标准API的一部分被引入,使得能够在诸如TCP流和文件系统操做的上下文中经过8位的字节流进行交互。javascript
如今TypedArray
已经添加到ES6中,Buffer
类以一种更优化和适用于Node.js的方式实现了Uint8Array
的API。java
Buffer
类的实例似于整数数组,不过是对应V8堆外的固定大小的原始内存进行分配(堆外内存,不受V8引擎控制)。 缓冲区的大小在建立时已经肯定,不能调整大小。node
Buffer
类是Node.js中的一个全局变量,所以不须要使用require('buffer').Buffer
。数组
// 建立一个长度为10的『0填充』Buffer实例 const buf1 = Buffer.alloc(10); // 建立一个长度为10的Buffer,填充0x1 const buf2 = Buffer.alloc(10, 0x1); // 建立一个长度为10的未初始化缓冲区 // 这个方法比使用Buffer.alloc()快,可是返回的Buffer实例可能包含以前的老数据。 // 须要使用fill()或write()重写。 const buf3 = Buffer.allocUnsafe(10); // 建立一个包含[0x1, 0x2, 0x3]的缓冲区 const buf4 = Buffer.from([1, 2, 3]); // 建立一个包含UTF-8字节[0x74, 0xc3, 0xa9, 0x73, 0x74]的缓冲区 const buf5 = Buffer.from('tést'); // 建立一个包含Latin-1字节[0x74, 0xe9, 0x73, 0x74]的缓冲区 const buf6 = Buffer.from('tést', 'latin-1');
在v6以前的Node.js版本中,使用Buffer构造函数建立了Buffer实例,该函数根据提供的参数以不一样的方式分配返回的Buffer:浏览器
将一个数字做为第一个参数传递给Buffer()
(例如new Buffer(10)
),分配一个指定大小的新的Buffer
对象。 为这些缓冲区实例分配的内存不会被初始化,而且可能包含敏感数据。 这种缓冲区实例必须经过使用buf.fill(0)
或彻底写入缓冲区来手动初始化。 虽然这种行为是为了提升性能,可是开发经验代表,建立一个快速但未初始化的缓冲区和建立一个更慢但更安全的缓冲区之间须要更明确的区分。安全
传递字符串,数组或Buffer做为第一个参数将传递的对象的数据复制到缓冲区中。bash
传递ArrayBuffer
返回一个与给定的ArrayBuffer
共享已分配内存的Buffer。服务器
由于new Buffer()
的行为是基于第一个参数传递的值的类型来选择具体操做,若是没有传递正确的参数给给new Buffer()
或未能适当地初始化新分配的Buffer
中缓冲区内容。那么此类应用将在无心中将安全性和可靠性的相关问题引入到他们的代码中。函数
为了使缓冲区实例的建立更可靠,出现更少的错误,new Buffer()
造函数的这种形式已被弃用,使用Buffer.from()
,Buffer.alloc()
或Buffer.allocUnsafe()
方法来代替。性能
开发人员应该将如今使用的new Buffer()
函数迁移到如下这些新的API之一。
Buffer.from(array)
返回一个包含所提供的八位字节的副本的新缓冲区。
Buffer.from(arrayBuffer [,byteOffset [,length]])
返回一个新的缓冲区,它与给定的ArrayBuffer
共享相同的分配内存。
Buffer.from(buffer)
返回一个包含给定Buffer的内容的副本的新缓冲区。
Buffer.from(string [,encoding])
返回一个包含所提供字符串副本的新缓冲区。
Buffer.alloc(size [,fill [,encoding]])
返回指定大小的“已填充”Buffer实例。 此方法虽然明显慢于Buffer.allocUnsafe(size)
方法,但它能够确保新建立的Buffer实例不会包含旧的和潜在的敏感数据。
Buffer.allocUnsafe(size)
和Buffer.allocUnsafeSlow(size)
都返回一个指定大小的新的缓冲区,其内容必须使用buf.fill(0)初始化或彻底写入新的内容以覆盖旧的敏感数据。
Buffer.allocUnsafe()
返回的缓冲区实例的大小小于或等于Buffer.poolSize
的一半那么能够在内部共享内存池中进行分配。 而Buffer.allocUnsafeSlow()
返回的实例不会使用内部共享内存池。
--zero-fill-buffers
命令行参数Node.js可使用--zero-fill-buffers
命令行参数启动,强制全部新分配的Buffer实例在使用new Buffer(size)
,Buffer.allocUnsafe()
,Buffer.allocUnsafeSlow()
或者new SlowBuffer()
在建立时自动0
。 使用此参数会更改这些方法的默认行为,而且会对性能产生重大影响。 建议仅在必要时强制使用--zero-fill-buffers
选项,以确保新分配的缓冲区实例不会包含潜在敏感数据。
$ node --zero-fill-buffers > Buffer.allocUnsafe(5); <Buffer 00 00 00 00 00>
Buffer.allocUnsafe()
和Buffer.allocUnsafeSlow()
不安全?当调用Buffer.allocUnsafe()
和Buffer.allocUnsafeSlow()
时,分配的内存段未初始化(不归0
)。 虽然该设计使得存储器的分配至关快,可是所分配的存储器段可能包含潜在敏感的旧数据。 使用由Buffer.allocUnsafe()
建立的缓冲区而不彻底从新覆盖的内存可能在读取缓冲区内存时泄漏这些旧数据。
虽然使用Buffer.allocUnsafe()
有明显的性能优点,但必须格外当心,以免将安全漏洞引入应用程序。
Buffer
实例一般用于表示编码字符的序列,例如UTF-8,UCS2,Base64甚至Hex编码数据。 能够经过使用字符编码声明字符串
在缓冲区实例和普通JavaScript字符串之间来回转换。
const buf = Buffer.from('hello world', 'ascii'); console.log(buf.toString('hex')); // => 68656c6c6f20776f726c64 console.log(buf.toString('base64')); // => aGVsbG8gd29ybGQ=
Node.js当前支持的字符编码包括:
ascii
utf8
utf16le
ucs2
base64
latin1
binary
hex
注意:当今的浏览器遵循WHATWG规范,将“latin1”和ISO-8859-1都合并到win-1252。 这意味着,当作相似于http.get()的操做时,若是返回的字符集是在WHATWG规范列出的范围内,服务器可能实际返回的是win-1252的编码数据,此时使用“latin1”编码可能会错误地解码字符,从而出现乱码。
Buffer
实例也是Uint8Array
实例。 可是,与ECMAScript 2015中的TypedArray
规范有一点点的不兼容。例如,当ArrayBuffer#slice()
建了一个slice的副本时,Buffer#slice()
实现建立了一个没有复制的现有Buffer
的副本,使得Buffer#slice()
更有效率。
Buffer中建立新的TypedArray实例时须要注意如下事项:
Buffer对象的内存是从TypedArray复制过来的,不是共享。
Buffer对象的内存能够解释为不一样元素的数组,而不是目标类型的字节数组。 也就是说,new Uint32Array(Buffer.from([1,2,3,4]))
是经过数组[1,2,3,4]建立一个长度为4的Uint32Array
,而不是经过[0x1020304]
或[0x4030201]
建立一个长度为1的Uint32Array
。
能够经过使用TypeArray对象的.buffer
属性建立一个新的Buffer,它与TypedArray实例共享相同的分配内存。
const arr = new Uint16Array(2); arr[0] = 5000; arr[1] = 4000; const buf1 = Buffer.from(arr); const buf2 = Buffer.from(arr.buffer); console.log(buf1); // => <Buffer 88 a0> console.log(buf2); // => <Buffer 88 13 a0 0f> arr[1] = 6000; console.log(buf1); // => <Buffer 88 a0> console.log(buf2); // => <Buffer 88 13 70 17>
注意,当使用TypedArray的
.buffer
建立一个Buffer时,能够经过传递byteOffset
和length
参数来使用ArrayBuffer的一部份内容。
const arr = new Uint16Array(20); const buf = new Buffer.from(arr.buffer, 0, 16); console.log(buf.length); // => 16
Buffer.from()
和TypedArray.from()
有不一样的函数签名和实现。 具体来讲,TypedArray
变量接受第二个参数,它是在类型数组的每一个元素上调用的映射函数:
TypedArray.from(source[, mapFn[, thisArg]])
Float32Array.from([1, 2, 3], x => x + x); // Float32Array [ 2, 4, 6 ]
然而,Buffer.from()
方法不支持使用映射函数:
Buffer.from(array)
Buffer.from(buffer)
Buffer.from(arrayBuffer[, byteOffset [, length]])
Buffer.from(string[, encoding])
可使用ECMAScript 2015(ES6)for..of
语法对缓冲区实例进行迭代。
const buf = Buffer.from([1, 2, 3]); for (const b of buf) { console.log(b)); // => 1 2 3 }
此外,buf.values()
,buf.keys()
和buf.entries()
方法均可用于建立迭代器。