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
,默认值为0
sourceStart
,默认值为0
sourceEnd
,默认值为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 - 8
noAssert
,布尔值,默认值为 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 - 4
noAssert
,布尔值,默认值为 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 - 1
noAssert
,布尔值,默认值为 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 - 2
noAssert
,布尔值,默认值为 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 - 4
noAssert
,布尔值,默认值为 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 - byteLength
byteLength
,数值,取值范围为0 < byteLength <= 6
noAssert
,布尔值,默认值为 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 - 1
noAssert
,布尔值,默认值为 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 - 2
noAssert
,布尔值,默认值为 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 - 4
noAssert
,布尔值,默认值为 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 - byteLength
byteLength
,数值,取值范围为0 < byteLength <= 6
noAssert
,布尔值,默认值为 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
,字符串,默认值为utf8
start
,数值,默认值为 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 - offset
encoding
,字符串,默认值为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 - 8
noAssert
,布尔值,默认值为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 - 4
noAssert
,布尔值,默认值为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 - 1
noAssert
,布尔值,默认值为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 - 2
noAssert
,布尔值,默认值为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 - 4
noAssert
,布尔值,默认值为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 - byteLength
byteLength
,数值,取值范围0 < byteLength <= 6
noAssert
,布尔值,默认值为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 - 1
noAssert
,布尔值,默认值为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 - 2
noAssert
,布尔值,默认值为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 - 4
noAssert
,布尔值,默认值为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 - byteLength
byteLength
,数值,取值范围0 < byteLength <= 6
noAssert
,布尔值,默认值为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 实例的方式应该被视为一种最终手段,除非开发者观察到应用中有过多不必要的内存,否则不要使用这种方式。