Buffer
在 ECMAScript 2015(ES6)引入 TypedArray 之前,JavaScript 语言中并没有读取和操作二进制数据流的机制。Node.js API 中的 Buffer 类提供了处理八进制数据流的能力,常用于处理 TCP 数据流和文件操作。
在 ES6 增加了 TypedArray 类型之后,Buffer 类基于 Uint8Array 接口做了定向优化, 从而使其更适用于 Node.js 的实际需求。
Buffer 类的实例非常类似整数数组,但其大小是固定不变的,在 V8 堆栈外分配原始内存空间。Buffer 类的实例创建之后,其所占用的内存大小就不能再进行调整。
Buffer 类是 Node.js 的全局对象,所以不需要使用 require() 而直接使用:
// Creates a zero-filled Buffer of length 10.
const buf1 = Buffer.alloc(10);
// Creates a Buffer of length 10, filled with 0x1.
const buf2 = Buffer.alloc(10, 1);
// Creates an uninitialized buffer of length 10.
// This is faster than calling Buffer.alloc() but the returned
// Buffer instance might contain old data that needs to be
// overwritten using either fill() or write().
const buf3 = Buffer.allocUnsafe(10);
// Creates a Buffer containing [0x1, 0x2, 0x3].
const buf4 = Buffer.from([1, 2, 3]);
// Creates a Buffer containing ASCII bytes [0x74, 0x65, 0x73, 0x74].
const buf5 = Buffer.from('test');
// Creates a Buffer containing UTF-8 bytes [0x74, 0xc3, 0xa9, 0x73, 0x74].
const buf6 = Buffer.from('tést', 'utf8');
Buffer.from() / Buffer.alloc() / Buffer.allocUnsafe()
在 Node.js v6.x 之前,通常使用 new Buffer() 创建 Buffer 实例,其缺点在于系统会根据参数类型的不同而返回不同类型的 Buffer 实例:
- 如果传入的第一个参数是数值(比如
new Buffer(10)),则生成一个特定长度的 Buffer 实例,但是此类 Buffer 实例分配到的内存是未经初始化和包含敏感数据的内存。此类 Buffer 实例必须通过buf.fill(0)或一次完整的数据重写手动完成内存的初始化操作。虽然这种方法的设计初衷是改善性能,但是过往的开发经验表明,对于创建快速未初始化(fast-but-uninitialized)和慢速已初始化(slower-but-safer)的 Buffer 实例,我们需要职责更加清晰的构造函数 - 如果传入的第一个参数是字符串、数组或 Buffer 实例,则系统会将它们的数据拷贝到新的 Buffer 实例中
- 如果传入的参数是 ArrayBuffer 的实例,则生成的 Buffer 实例与该 ArrayBuffer 实例共享同一段内存
由于 new Buffer() 会根据第一个参数的类型触发不同的处理逻辑,所以当应用程序没有正确校验 new Buffer() 的参数或没有正确初始化 Buffer 实例的内容时,就会在不经意间向代码中引入安全性和可靠性问题。
为了避免 Buffer 实例的此类问题,建议使用 Buffer.from()、Buffer.alloc() 和 Buffer.allocUnsafe() 方法替代 new Buffer()。
开发者应该使用以下函数替换 new Buffer() 的操作:
Buffer.from(array),创建并返回一个包含array数据的 Buffer 实例Buffer.from(arrayBuffer[, byteOffset [, length]]),创建并返回一个与ArrayBuffer共享内存片段的 Buffer 实例Buffer.from(buffer),创建并返回一个包含buffer数据的 Buffer 实例Buffer.from(str[, encoding]),创建并返回一个包含str数据的 Buffer 实例Buffer.alloc(size[, fill[, encoding]]),创建并返回一个已初始化的 Buffer 实例,长度为size,该方法在性能上虽然明显比Buffer.allocUnsafe(size)慢很多,但可以保证新建的 Buffer 实例绝对不会包含敏感或遗留数据Buffer.allocUnsafe(size)和Buffer.allocUnsafeSlow(size)都会返回size大小的 Buffer 实例,但不会自动初始化内存片段,必须使用buf.fill(0)或重写内存片段的方式进行初始化。
如果 Buffer.allocUnsafe(size) 的 size 小于或等于 Buffer.poolSize 的一半,那么 Buffer 实例就有可能由内部共享的内存池分配内存片段,而使用 Buffer.allocUnsafeSlow(size) 生成的 Buffer 实例则不会使用内部共享的内存池。
--zero-fill-buffers
如果在命令行启动 Node.js 时附加 --zero-fill-buffers 参数,则强制新建 Buffer 实例时自动将内存片段初始化为 0。使用该参数会改变系统的默认行为,并对系统性能造成影响。建议只在处理非敏感数据时使用该参数:
$ node --zero-fill-buffers
> Buffer.allocUnsafe(5);
<Buffer 00 00 00 00 00>
为什么 Buffer.allocUnsafe(size) 和 Buffer.allocUnsafeSlow(size) 不安全?
通过 Buffer.allocUnsafe(size) 和 Buffer.allocUnsafeSlow(size) 生成的 Buffer 实例,其内存片段都是未经初始化的。虽然这种操作执行速度快,但这些内存片段可能包含敏感的历史数据,那么当系统读取 Buffer 实例时,就有可能发生内存泄露。
虽然 Buffer.allocUnsafe() 的执行性能很好,但使用时必须十分小心,避免因此造成安全问题。
Buffer 和字符编码
Buffer 实例常用于处理编码后的字符序列,比如 UTF8 / UCS2 / Base64 甚至是十六进制编码后的数据。通过指定字符编码,数据可以在 Buffer 实例和原始的 JavaScript 字符串之间来回转换:
const buf = Buffer.from('hello world', 'ascii');
// Prints: 68656c6c6f20776f726c64
console.log(buf.toString('hex'));
// Prints: aGVsbG8gd29ybGQ=
console.log(buf.toString('base64'));
当前 Node.js 支持以下字符编码格式:
ascii,仅支持 7 位(7-bit)的 ASCII 字符,该方法解析速度快,还可以自动去除高位字节utf8,使用多字节对 unicode 字符进行编码。诸多 web 页面和文档都在采用 UTF-8 编码规范utf16le,使用二到四个字节、小端字节序对 unicode 字符进行编码,支持解码代理对(surrogate pair, U+10000 ~ U+10FFFF)ucs2,utf16le的别名。base64,Base64 编码。对于使用字符串创建的 Buffer 实例,base64编码格式允许该字符串是 RFC4648, Section 5 中指定的 URL 和文件名安全字符集(URL and Filename Safe Alphabet)。latin1,将 Buffer 实例转换为单字节(latin-1)字符串的编码格式(as defined by the IANA in RFC1345, page 63, to be the Latin-1 supplement block and C0/C1 control codes)binary,latin1的别名hex,将每个字节转换为两个十六进制的字符
当今浏览器一般都遵循了 WHATWG 规范 ,该规范将
latin1和ISO-8859都视为是win-1252的别名。这意味着,如果你通过http.get()获取到后端数据,且数据编码格式是上述 WHATWG 规范中规定的一种,那么你很有可能会接收到编码格式为win-1252的数据,此时使用latin1格式对数据解码就有可能会出错。
Buffer 和 TypedArray
Buffer 实例实际上也是 TypedArray 中 Uint8Array 的实例。不过,这里的 TypedArray 与 ECMAScript 2015 规范所规定的 TypedArray 稍有不同。举例来说,ECMAScript 2015 规范规定 ArrayBuffer#slice() 方法创建一个内存拷贝,而 Node.js 中 Buffer#slice() 则会根据既有的 Buffer 实例新建一个视图(View,译者注:ES2015 中有两种视图,分别是 TypedArray 和 DataView),而不是拷贝数据,从而提高执行效率。
基于一个 Buffer 实例创建一个 TypedArray 实例需要注意以下几点事项:
Buffer实例的内存数据会被拷贝到TypedArray实例中,它们之间不是内存共享的关系。Buffer实例的内存数据会被解释为一个直观的整数数组,而不是一个特定类型的单字节数组。举例来说,new Uint32Array(new Buffer([1,2,3,4]))会创建一个Uint32Array视图,它包含[1,2,3,4]四个元素,而不是创建一个Uint32Array类型的单元素数组[0x1020304]或[0x4030201]。
如果要创建一个和 TypedArray 实例共享内存的 Buffer 实例,可以使用 TypedArray 实例的 .buffer 属性:
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// Copies the contents of `arr`
const buf1 = Buffer.from(arr);
// Shares memory with `arr`
const buf2 = Buffer.from(arr.buffer);
// Prints: <Buffer 88 a0>
console.log(buf1);
// Prints: <Buffer 88 13 a0 0f>
console.log(buf2);
arr[1] = 6000;
// Prints: <Buffer 88 a0>
console.log(buf1);
// Prints: <Buffer 88 13 70 17>
console.log(buf2);
使用 TypedArray 实例的 .buffer 属性创建 Buffer 实例时,可以使用 byteOffset 和 length 参数截取 ArrayBuffer 实例的内存数据:
const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
// Prints: 16
console.log(buf.length);
Buffer.from() 和 TypedArray.from()(比如 Uint8Array.from())拥有不同的参数和实现,举例来说,TypedArray 接收一个映射函数(mapping function)作为第二个参数,该函数会遍历处理 TypedArray 实例的每一个元素:
TypedArray.from(source[, mapFn[, thisArg]])
但是 Buffer.from 函数不具有这种用法:
Buffer.from(array)Buffer.from(buffer)Buffer.from(arrayBuffer[, byteOffset [, length]])Buffer.from(str[, encoding])
Buffers 和 ES6 遍历器
使用 ECMAScript 2015 提供的 for...of 语法可以遍历 Buffer 实例:
const buf = Buffer.from([1, 2, 3]);
// Prints:
// 1
// 2
// 3
for (var b of buf) {
console.log(b);
}
此外,使用 buf.values()、buf.keys() 和 buf.entries() 函数可以创建遍历器实例。
Class: Buffer
Buffer 类是一个用于处理二进制数据的全局对象。通过该对象,Node.js 提供了多种方法来创建 Buffer 实例。
new Buffer()
从 Node.js 6+ 开始,已废弃该构造函数,使用以下函数替换:
- 使用
Buffer.from(array)替换new Buffer(array) - 使用
Buffer.from(buffer)替换new Buffer(buffer) - 使用
Buffer.from(arrayBuffer[, byteOffset[, length]])替换new Buffer(arrayBuffer[, byteOffset[, length]]) - 使用
Buffer.alloc(size)或Buffer.allocUnsafe(size)替换new Buffer(size) - 使用
Buffer.from(string[, encoding])替换new Buffer(string[, encoding])
Buffer.alloc(size[, fill[, encoding]])
成员方法:Buffer.byteLength(string[, encoding])
string,字符串encoding,字符串格式的可选参数,默认值为utf8- 返回值类型:Number
返回字符串的实际字节长度。与 String.prototype.length 不同的是,该方法返回数值表示字符串占多少字节,而 String.prototype.length 返回的数值表示字符串有多少个字符。
const str = '\u00bd + \u00bc = \u00be';
console.log(`${str}: ${str.length} characters, ` +
`${Buffer.byteLength(str, 'utf8')} bytes`);
// ½ + ¼ = ¾: 9 个字符, 12 个字节
成员方法:Buffer.compare(buf1, buf2)
buf1,Buffer 实例buf2,Buffer 实例- 返回值类型:Number
比较 buf1 和 buf2 常常是为了对 Buffer 实例的数组进行排序,该方法等同于 buf1.compare(buf2):
const arr = [Buffer('1234'), Buffer('0123')];
arr.sort(Buffer.compare);
成员方法:Buffer.concat(list[, totalLength])
list,用于合并的 Buffer 实例数组- `totalLength,数值类型的可选参数,用于说明数组中所有 Buffer 实例的字节之和
- 返回值类型:Buffer
返回一个 Buffer 实例,该实例是传入的 Buffer 实例数组中所有元素合并后生成的。如果实例数组为空,或者 totalLength 为 0,则返回一个长度为 0 的 Buffer 实例。
如果没有传入 totalLength 参数,则系统根据 list 参数中所有实例的大小自动求取。不过,这需要系统通过循环计算出来字节总数,所以通过提供该参数可以提高系统的执行效率。
const buf1 = new Buffer(10).fill(0);
const buf2 = new Buffer(14).fill(0);
const buf3 = new Buffer(18).fill(0);
const totalLength = buf1.length + buf2.length + buf3.length;
console.log(totalLength);
const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
console.log(bufA);
console.log(bufA.length);
// 42
// <Buffer 00 00 00 00 ...>
// 42
成员方法:Buffer.isBuffer(obj)
obj,对象类型的参数- 返回值类型:Boolean
如果 obj 为 Buffer 实例,则返回 true,反之异然。
成员方法:Buffer.isEncoding(encoding)
encoding,字符串形式的字符串编码说明- 返回值类型:Boolean
如果 encoding 参数为合法的字符串编码,则返回 true,反之异然。
buf[index]
[index] 索引操作可以用于从 Buffer 实例的指定位置存取(get and set)二进制数据。index 的值为单字节数据,所以在这里索引的合法范围是 0x00 ~ 0xFF(十六进制)或者 0 ~ 255(十进制)。
const str = "Node.js";
const buf = new Buffer(str.length);
for (var i = 0; i < str.length ; i++) {
buf[i] = str.charCodeAt(i);
}
console.log(buf);
// 输出结果: Node.js
buf.compare(otherBuffer)
otherBuffer,Buffer 实例- 返回值类型:Number
比较两个 Buffer 实例,返回一个数值,用于标识 buf 和 otherBuffer 的先后顺序。比较过程是基于每个 Buffer 实例的元素顺序进行的。
0表示buf和otherBuffer相同1表示排序时otherBuffer应该排在buf之前-1表示排序时otherBuffer应该排在buf之后
const buf1 = new Buffer('ABC');
const buf2 = new Buffer('BCD');
const buf3 = new Buffer('ABCD');
console.log(buf1.compare(buf1));
// 输出结果: 0
console.log(buf1.compare(buf2));
// 输出结果: -1
console.log(buf1.compare(buf3));
// 输出结果: -1
console.log(buf2.compare(buf1));
// 输出结果: 1
console.log(buf2.compare(buf3));
// 输出结果: 1
[buf1, buf2, buf3].sort(Buffer.compare);
// 输出结果: [buf1, buf3, buf2]
buf.copy(targetBuffer[, targetSet[, sourceStart[, sourceEnd]]])
targetBuffer,Buffer 实例,拷贝目标(将 buf 的数据拷贝到 targetBuffer)targetStart,默认值为0sourceStart,默认值为0sourceEnd,默认值为buffer.length- 返回值类型:Number,说明拷贝的字节总数
该方法用于将数据从 buf 拷贝到 targetBuffer,即使对自身进行拷贝也没有问题。
const buf1 = new Buffer(26);
const buf2 = new Buffer(26).fill('!');
for (var i = 0 ; i < 26 ; i++) {
buf1[i] = i + 97; // 97 is ASCII a
}
buf1.copy(buf2, 8, 16, 20);
console.log(buf2.toString('ascii', 0, 25));
// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
下面代码演示了对自身进行的拷贝:
const buf = new Buffer(26);
for (var i = 0 ; i < 26 ; i++) {
buf[i] = i + 97; // 97 is ASCII a
}
buf.copy(buf, 0, 4, 10);
console.log(buf.toString());
// efghijghijklmnopqrstuvwxyz
buf.entries()
- 返回值类型:Iterator
根据 Buffer 实例的数据创建并返回一个格式为 [index, byte] 的遍历器:
const buf = new Buffer('buffer');
for (var pair of buf.entries()) {
console.log(pair);
}
// 输出结果:
// [0, 98]
// [1, 117]
// [2, 102]
// [3, 102]
// [4, 101]
// [5, 114]
buf.equals(otherBuffer)
otherBuffer,Buffer 实例- 返回值类型:Boolean
该方法用于判断两个 Buffer 实例是否具有相同的值,如果相等则返回 true,反之异然。
const buf1 = new Buffer('ABC');
const buf2 = new Buffer('414243', 'hex');
const buf3 = new Buffer('ABCD');
console.log(buf1.equals(buf2));
// 输出结果: true
console.log(buf1.equals(buf3));
// 输出结果: false
buf.fill(value[, offset[, end]])
value,字符串或者数值offset,数值,默认值为 0end,数值,默认值为buffer.length- 返回值类型:Buffer
将 Buffer 实例的每个值置为 value 参数所表示的值。如果未传入了 offset 和 end 参数,默认重置 Buffer 实例的所有元素。因为该实例方法返回 Buffer 实例自身,所以可以执行链式调用。
const b = new Buffer(50).fill('h');
console.log(b.toString());
// 输出结果: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
buf.indexOf(vlaue[, byteOffset][, encoding])
value,字符串,Buffer 实例或者数值byteOffset,默认值为 0encoding,默认值为 'utf8'- 返回值类型:Number
该实例方法类似于 Array#indexOf() 方法,如果查找成功,则返回 value 的起始位置;如果查找失败,则返回 -1。value 参数可以是字符串、Buffer 实例或者数值。如果传入的 vlaue 参数是字符串类型,默认被解释为 UTF8 编码格式;如果传入的 value 参数是 Buffer 实例,默认查找与 Buffer 实例整体内容相匹配的值(使用 buf.slice() 可以查找 Buffer 实例的部分值);如果传入的 value 参数是数值类型,则只能使用 0 ~ 255 之间数值(如果值为负,则表示从后往前查找)。
const buf = new Buffer('this is a buffer');
buf.indexOf('this');
// 返回值: 0
buf.indexOf('is');
// 返回值: 2
buf.indexOf(new Buffer('a buffer'));
// 返回值: 8
buf.indexOf(97);
// ascii for 'a'
// 返回值: 8
buf.indexOf(new Buffer('a buffer example'));
// 返回值: -1
buf.indexOf(new Buffer('a buffer example').slice(0,8));
// 返回值: 8
const utf16Buffer = new Buffer('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
utf16Buffer.indexOf('\u03a3', 0, 'ucs2');
// 返回值: 4
utf16Buffer.indexOf('\u03a3', -4, 'ucs2');
// 返回值: 6
buf.includes(value[, byteOffset][, encoding])
value,字符串,Buffer 实例或者数值byteOffset,默认值为 0encoding,默认值为 'utf8'- 返回值类型:Number
该实例方法类似于 Array#includes(),其中 value 参数可以是字符串、Buffer 实例或者数值。。如果传入的 vlaue 参数是字符串类型,默认被解释为 UTF8 编码格式;如果传入的 value 参数是 Buffer 实例,默认查找与 Buffer 实例整体内容相匹配的值(使用 buf.slice() 可以查找 Buffer 实例的部分值);如果传入的 value 参数是数值类型,则只能使用 0 ~ 255 之间数值(如果值为负,则表示从后往前查找)。
可选参数 byteOffset 表示在 buf 中检索的起点位置:
const buf = new Buffer('this is a buffer');
buf.includes('this');
// 返回结果: true
buf.includes('is');
// 返回结果: true
buf.includes(new Buffer('a buffer'));
// 返回结果: true
buf.includes(97);
// ascii for 'a'
// 返回结果: true
buf.includes(new Buffer('a buffer example'));
// 返回结果: false
buf.includes(new Buffer('a buffer example').slice(0,8));
// 返回结果: true
buf.includes('this', 4);
// 返回结果: false
buf.keys()
- 返回值类型:Iterator
根据 Buffer 实例的键创建和返回一个 Iterator:
const buf = new Buffer('buffer');
for (var key of buf.keys()) {
console.log(key);
}
// 返回结果:
// 0
// 1
// 2
// 3
// 4
// 5
buf.length
- 返回值类型:Number
该属性返回 Buffer 实例在内存中所占有的字节大小。值得注意的是,该属性并不表示 Buffer 实例的使用量,比如下面的这个例子,虽然 Buffer 实例占有 1234 个字节,但是只有 11 个字节用于存储 ASCII 字符,其他空间处于闲置状态:
const buf = new Buffer(1234);
console.log(buf.length);
// 输出结果: 1234
buf.write('some string', 0, 'ascii');
console.log(buf.length);
// 输出结果: 1234
该属性是不可变属性(immutable),修改该属性将会返回 undefined,且会影响 Buffer 实例的正常使用。如果你想修改 length 属性,可以变通地使用 buf.slice() 方法创建一个新 Buffer 实例:
const buf = new Buffer(10);
buf.write('abcdefghj', 0, 'ascii');
console.log(buf.length);
// 输出结果: 10
buf = buf.slice(0,5);
console.log(buf.length);
// 输出结果: 5
buf.rendDoubleBE(offset[, noAssert])
buf.rendDoubleLE(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 8noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 64 位的双精度浮点数(double 类型),如果使用的是 readDoubleBE(),则使用大端字节序读取;如果使用的是 readDoubleLE(),则使用小端字节序读取。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 8。
const buf = new Buffer([1,2,3,4,5,6,7,8]);
buf.readDoubleBE();
// 返回结果: 8.20788039913184e-304
buf.readDoubleLE();
// 返回结果: 5.447603722011605e-270
buf.readDoubleLE(1);
// throws RangeError: 索引越界
buf.readDoubleLE(1, true);
// Warning: reads passed end of buffer!
// Segmentation fault! don't do this!
buf.rendFloatBE(offset[, noAssert])
buf.rendFloatLE(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 4noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 32 位的单精度浮点数(float 类型),如果使用的是 readFloatBE(),则使用大端字节序读取;如果使用的是 readFloatLE(),则使用小端字节序读取。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 4。
const buf = new Buffer([1,2,3,4]);
buf.readFloatBE();
// 返回结果: 2.387939260590663e-38
buf.readFloatLE();
// 返回结果: 1.539989614439558e-36
buf.readFloatLE(1);
// throws RangeError: 索引越界
buf.readFloatLE(1, true);
// Warning: reads passed end of buffer!
// Segmentation fault! don't do this!
buf.reanInt8(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 1noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个单字节整数(int 类型)。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 1。
const buf = new Buffer([1,-2,3,4]);
buf.readInt8(0);
// 返回结果: 1
buf.readInt8(1);
// 返回结果: -2
buf.readInt16BE(offset[, noAssert])
buf.readInt16LE(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 2noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 16 位的双字节整数(int 类型),如果使用的是 readInt16BE(),则使用大端字节序读取;如果使用的是 readInt16LE(),则使用小端字节序读取。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 2。
const buf = new Buffer([1,-2,3,4]);
buf.readInt16BE();
// 返回结果: 510
buf.readInt16LE();
// 返回结果: -511
buf.readInt32BE(offset[, noAssert])
buf.readInt32LE(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 4noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 32 位的双字节整数(int 类型),如果使用的是 readInt32BE(),则使用大端字节序读取;如果使用的是 readInt32LE(),则使用小端字节序读取。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 4。
const buf = new Buffer([1,-2,3,4]);
buf.readInt32BE();
// 返回结果: 33424132
buf.readInt32LE();
// 返回结果: 67370497
buf.readIntBE(offset, byteLength[, noAssert])
buf.readIntLE(offset, byteLength[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - byteLengthbyteLength,数值,取值范围为0 < byteLength <= 6noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个长度为 byteLength 的字节,最高精度为 48 位。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - byteLength。
const buf = new Buffer(6);
buf.writeUInt16LE(0x90ab, 0);
buf.writeUInt32LE(0x12345678, 2);
buf.readIntLE(0, 6).toString(16);
// 返回结果: '1234567890ab'
buf.readIntBE(0, 6).toString(16);
// 返回结果: -546f87a9cbee
buf.readUInt8(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 1noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 8 位的无符号整数。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 1。
const buf = new Buffer([1,-2,3,4]);
buf.readUInt8(0);
// 返回结果: 1
buf.readUInt8(1);
// 返回结果: 254
buf.readUInt16BE(offset[, noAssert])
buf.readUInt16LE(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 2noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 16 位的无符号整数(int 类型),如果使用的是 readUInt16BE(),则使用大端字节序读取;如果使用的是 readUInt16LE(),则使用小端字节序读取。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 2。
const buf = new Buffer([0x3, 0x4, 0x23, 0x42]);
buf.readUInt16BE(0);
// 返回结果: 0x0304
buf.readUInt16LE(0);
// 返回结果: 0x0403
buf.readUInt16BE(1);
// 返回结果: 0x0423
buf.readUInt16LE(1);
// 返回结果: 0x2304
buf.readUInt16BE(2);
// 返回结果: 0x2342
buf.readUInt16LE(2);
// 返回结果: 0x4223
buf.readUInt32BE(offset[, noAssert])
buf.readUInt32LE(offset[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - 4noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个 32 位的无符号整数(int 类型),如果使用的是 readUInt32BE(),则使用大端字节序读取;如果使用的是 readUInt32LE(),则使用小端字节序读取。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 4。
const buf = new Buffer([0x3, 0x4, 0x23, 0x42]);
buf.readUInt32BE(0);
// 返回结果: 0x03042342
console.log(buf.readUInt32LE(0));
// 返回结果: 0x42230403
buf.readUIntBE(offset, byteLength[, noAssert])
buf.readUIntLE(offset, byteLength[, noAssert])
offset,数值,取值范围为0 <= offset <= buf.length - byteLengthbyteLength,数值,取值范围为0 < byteLength <= 6noAssert,布尔值,默认值为 false- 返回值类型:Number
从 Buffer 实例中 offset 位置开始读取一个长度为 byteLength 的字节,最高精度为 48 位。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - byteLength。
const buf = new Buffer(6);
buf.writeUInt16LE(0x90ab, 0);
buf.writeUInt32LE(0x12345678, 2);
buf.readUIntLE(0, 6).toString(16);
// 返回结果: '1234567890ab'
buf.readUIntBE(0, 6).toString(16);
// 返回结果: ab9078563412
buf.slice([start[, end]])
start,数值,默认值为 0end,数值,默认值为buffer.length- 返回值类型:Buffer
根据可选参数 start 和 end 指定的位置从 buf 中切片出新的 Buffer 实例,且它们共享同一段内存。
因为两个 Buffer 实例共享内存,所以其中一个实例修改数据后,另一个实例得到的就是修改后的数据。
const buf1 = new Buffer(26);
for (var i = 0 ; i < 26 ; i++) {
buf1[i] = i + 97; // 97 is ASCII a
}
const buf2 = buf1.slice(0, 3);
buf2.toString('ascii', 0, buf2.length);
// 返回结果: 'abc'
buf1[0] = 33;
buf2.toString('ascii', 0, buf2.length);
// 返回结果 : '!bc'
使用负值索引可以从后往前执行切片:
const buf = new Buffer('buffer');
buf.slice(-6, -1).toString();
// 返回结果: 'buffe', 等同于 buf.slice(0, 5)
buf.slice(-6, -2).toString();
// 返回结果: 'buff', 等同于 buf.slice(0, 4)
buf.slice(-5, -2).toString();
// 返回结果: 'uff', 等同于 buf.slice(1, 4)
buf.toString([encoding[, start[, end]]])
encoding,字符串,默认值为utf8start,数值,默认值为 0end,数值,默认值为buffer.length- 返回值类型:String
该方法根据 encoding 指定的编码格式,从 Buffer 实例存储的数据中编码和返回一个字符串:
const buf = new Buffer(26);
for (var i = 0 ; i < 26 ; i++) {
buf[i] = i + 97; // 97 is ASCII a
}
buf.toString('ascii');
// 返回结果: 'abcdefghijklmnopqrstuvwxyz'
buf.toString('ascii',0,5);
// 返回结果: 'abcde'
buf.toString('utf8',0,5);
// 返回结果: 'abcde'
buf.toString(undefined,0,5);
// 返回结果: 'abcde', encoding defaults to 'utf8'
buf.toJSON()
- 返回值类型:Object
该方法返回一个 JSON 对象,用于描述调用它的 Buffer 实例。如果 JSON.stringify() 收到的参数是一个 Buffer 实例,那么它会隐式调用 buf.toJSON() 进行解析:
const buf = new Buffer('test');
const json = JSON.stringify(buf);
console.log(json);
// 输出结果: '{"type":"Buffer","data":[116,101,115,116]}'
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer'
? new Buffer(value.data)
: value;
});
console.log(copy.toString());
// 输出结果: 'test'
buf.values()
- 返回值类型:Iterator
根据 Buffer 实例的值创建和返回一个 Iterator 对象。当使用 for...of 遍历 Buffer 实例时,系统会隐式调用该方法解析 Buffer 实例:
const buf = new Buffer('buffer');
for (var value of buf.values()) {
console.log(value);
}
// prints:
// 98
// 117
// 102
// 102
// 101
// 114
for (var value of buf) {
console.log(value);
}
// prints:
// 98
// 117
// 102
// 102
// 101
// 114
buf.write(string[, offset[, length[, encoding]]])
string,字符串,用于写入到 Buffer 实例中数据offset,数值,默认值为 0length,数值,默认值为buffer.length - offsetencoding,字符串,默认值为utf8- 返回值类型:Number,表示成功写入的字节数量
该方法按照 encoding 参数指定的编码格式从 offset 位置开始向 Buffer 实例中写入 string 参数所引用的数据。length 参数显式声明要写入到 Buffer 实例的字节数量。如果 Buffer 实例无法容纳所有写入的数据,那么就只会解析和写入部分数据:
const buf = new Buffer(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
// 输出结果: 12 bytes: ½ + ¼ = ¾
buf.writeDoubleBE(value, offset[, noAssert])
buf.writeDoubleLE(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 8noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,如果使用的是 writeDoubleBE(),则使用大端字节序写入;如果使用的是 writeDoubleLE(),则使用小端字节序写入。value 参数引用的数据必须是有效的 64 位双精度浮点数(double 类型)。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 8,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(8);
buf.writeDoubleBE(0xdeadbeefcafebabe, 0);
console.log(buf);
// 输出结果: <Buffer 43 eb d5 b7 dd f9 5f d7>
buf.writeDoubleLE(0xdeadbeefcafebabe, 0);
console.log(buf);
// 输出结果: <Buffer d7 5f f9 dd b7 d5 eb 43>
buf.writeFloatBE(value, offset[, noAssert])
buf.writeFloatLE(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 4noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,如果使用的是 writeFloatBE(),则使用大端字节序写入;如果使用的是 writeFloatLE(),则使用小端字节序写入。value 参数引用的数据必须是有效的 32 位单精度浮点数(float 类型)。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 4,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(4);
buf.writeFloatBE(0xcafebabe, 0);
console.log(buf);
// 输出结果: <Buffer 4f 4a fe bb>
buf.writeFloatLE(0xcafebabe, 0);
console.log(buf);
// 输出结果: <Buffer bb fe 4a 4f>
buf.writeInt8(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 1noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,该数据必须是有效地单字节整数(int 类型)。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 1,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(2);
buf.writeInt8(2, 0);
buf.writeInt8(-2, 1);
console.log(buf);
// 输出结果: <Buffer 02 fe>
buf.writeInt16BE(value, offset[, noAssert])
buf.writeInt16LE(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 2noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,如果使用的是 writeInt16BE(),则使用大端字节序写入;如果使用的是 writeInt16LE(),则使用小端字节序写入。value 参数引用的数据必须是有效的 16 位双字节整数。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 2,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(4);
buf.writeInt16BE(0x0102,0);
buf.writeInt16LE(0x0304,2);
console.log(buf);
// 输出结果: <Buffer 01 02 04 03>
buf.writeInt32BE(value, offset[, noAssert])
buf.writeInt32LE(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 4noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,如果使用的是 writeInt32BE(),则使用大端字节序写入;如果使用的是 writeInt32LE(),则使用小端字节序写入。value 参数引用的数据必须是有效的 32 位四字节整数。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 4,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(8);
buf.writeInt32BE(0x01020304,0);
buf.writeInt32LE(0x05060708,4);
console.log(buf);
// 输出结果: <Buffer 01 02 03 04 08 07 06 05>
buf.writeIntBE(value, offset, byteLength[, noAssert])
buf.writeIntLE(value, offset, byteLength[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - byteLengthbyteLength,数值,取值范围0 < byteLength <= 6noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,长度为 byteLength,最高精度为 48 位。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - byteLength,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf1 = new Buffer(6);
buf1.writeUIntBE(0x1234567890ab, 0, 6);
console.log(buf1);
// 输出结果: <Buffer 12 34 56 78 90 ab>
const buf2 = new Buffer(6);
buf2.writeUIntLE(0x1234567890ab, 0, 6);
console.log(buf2);
// 输出结果: <Buffer ab 90 78 56 34 12>
buf.writeUInt8(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 1noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,该数据必须是无符号的单字节整数(int 类型)。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 1,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(4);
buf.writeUInt8(0x3, 0);
buf.writeUInt8(0x4, 1);
buf.writeUInt8(0x23, 2);
buf.writeUInt8(0x42, 3);
console.log(buf);
// 输出结果: <Buffer 03 04 23 42>
buf.writeUInt16BE(value, offset[, noAssert])
buf.writeUInt16LE(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 2noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,如果使用的是 writeUInt16BE(),则使用大端字节序写入;如果使用的是 writeUInt16LE(),则使用小端字节序写入。value 参数引用的数据必须是无符号的双字节整数。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 2,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(4);
buf.writeUInt16BE(0xdead, 0);
buf.writeUInt16BE(0xbeef, 2);
console.log(buf);
// 输出结果: <Buffer de ad be ef>
buf.writeUInt16LE(0xdead, 0);
buf.writeUInt16LE(0xbeef, 2);
console.log(buf);
// 输出结果: <Buffer ad de ef be>
buf.writeUInt32BE(value, offset[, noAssert])
buf.writeUInt32LE(value, offset[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - 4noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,如果使用的是 writeUInt32BE(),则使用大端字节序写入;如果使用的是 writeUInt32LE(),则使用小端字节序写入。value 参数引用的数据必须是无符号的四字节整数。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - 4,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(4);
buf.writeUInt32BE(0xfeedface, 0);
console.log(buf);
// 输出结果: <Buffer fe ed fa ce>
buf.writeUInt32LE(0xfeedface, 0);
console.log(buf);
// 输出结果: <Buffer ce fa ed fe>
buf.writeUIntBE(value, offset, byteLength[, noAssert])
buf.writeUIntLE(value, offset, byteLength[, noAssert])
value,数值,用于写入到 Buffer 实例的数据offset,数值,取值范围0 <= offset <= buf.length - byteLengthbyteLength,数值,取值范围0 < byteLength <= 6noAssert,布尔值,默认值为false- 返回值类型:Number,表示成功写入的字节数量
从 Buffer 实例中 offset 位置开始写入 value 参数所引用的数据,长度为 byteLength,最高精度为 48 位。
如果传入可选参数 noAssert 且值为 true,则执行该方法时忽略参数 offset 是否符合取值范围 0 <= offset <= buf.length - byteLength,同时忽略 value 参数所引用的数据是否过长。除非确信数据的准确性,否则不建议忽略对 value 和 offset 参数的检查。
const buf = new Buffer(6);
buf.writeUIntBE(0x1234567890ab, 0, 6);
console.log(buf);
// 输出结果: <Buffer 12 34 56 78 90 ab>
buffer.INSPECT_MAX_BYTES
- 数值,默认值为 50
该属性用于设置 buffer.inspect() 方法返回的最大字节数,可以被开发者自定义的模块修改,更多有关 buffer.inspect() 方法的信息请参考 util.inspect() 方法。
值得注意的是,该属性并不挂载在全局对象 Buffer 或者 Buffer 实例上,而是存在于 require('buffer') 的返回值中。
Class: SlowBuffer
SlowBuffer 类用于创建 un-pooled(不放入内存池?)的 Buffer 实例。
为了降低创建 Buffer 实例的开销,避免 Buffer 实例冗杂凌乱的现象,默认情况下对于小于 4KB 的 Buffer 实例使用单个大内存对象存储和管理。这种方式可以有效提高性能和内存利用率,避免 V8 频繁追踪和清理过多的 Persistent 对象。
有时候,开发者希望对内存中的一小块空间保留一个不确定的时间,针对这种情况,就可以使用 SlowBuffer 类创建 un-pooled(不放入内存池?)的 Buffer 实例,然后通过内存拷贝获取目标数据:
// need to keep around a few small chunks of memory
const store = [];
socket.on('readable', () => {
var data = socket.read();
// allocate for retained data
var sb = new SlowBuffer(10);
// copy the data into the new allocation
data.copy(sb, 0, 0, 10);
store.push(sb);
});
通过 SlowBuffer 类创建 Buffer 实例的方式应该被视为一种最终手段,除非开发者观察到应用中有过多不必要的内存,否则不要使用这种方式。