Node.js—Buffer对象
1 概述
Buffer对象是Node处理二进制数据的一个接口。它是Node原生提供的全局对象,可以直接使用,不需要require("buffer")
导入。该对象提供了在Node中处理二进制数据的接口。
JavaScript比较擅长处理字符串,对于处理二进制数据(比如TCP数据流),就不太擅长。Buffer对象就是为了解决JavaScript在二进制数据处理上不足问题而设计的。
它是一个构造函数,Buffer对象是V8引擎分配的一段内存,类似数组,成员都为0到255的整数值,即一个8位的字节。
2 基本操作
Buffer的基本操作:
(1)创建:let bytes = new Buffer(size);
(2)切片:bytes.slice(start,end);
(3)拷贝:bytes.copy(目标缓冲区,目标缓冲区的起始位置,源缓冲区的起始位置,源缓冲区的结束位置)
(4)Buffer和字符串之间的互换:需要指定编码格式。支持的编码格式(ascii码、utf8、utf16le、ucs2、base64、hex)
示例:生成Buffer对象实例,以及它的赋值和取值
//生成一个256字节的Buffer实例
let bytes = new Buffer(256);
//遍历每个字节,写入内容
for (let i = 0; i < bytes.length; i++) {
bytes[i] = i;
}
//切片处理,从240到256字节
let end = bytes.slice(240, 256);
console.log(end[0]); // 240
end[0] = 0; // 将其设置为0
console.log(end[0]); // 0
console.log(end); // <Buffer 00 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff>
示例:拷贝生成Buffer实例
// 生成一个8个字节的Buffer实例
let bytes = new Buffer(8);
// 遍历每个字节,写入内容
for (let i = 0; i < bytes.length; i++) {
bytes[i] = i;
}
// 生产一个4个字节的Buffer实例
let more = new Buffer(4);
//copy方法将bytes实例的4号成员到7号成员的这一段,都拷贝到了more实例从0号成员开始的区域
bytes.copy(more, 0, 4, 8);
console.log(more); // <Buffer 04 05 06 07>
3 与二进制数组的关系
TypedArray对象描述了基础二进制数据缓冲区的类数组视图。没有名为TypedArray的全局属性,也没有直接可见的TypedArray构造函数。相反,有许多不同的全局属性,其值是特定元素类型的类型化数组构造函数,如下所示:
//创建TypedArray
const typedArray1 = new Int8Array(8);
typedArray1[0] = 32;
const typedArray2 = new Int8Array(typedArray1);
typedArray1[1] = 42;
console.log(typedArray1);
console.log(typedArray2);
TypedArray的类型及值范围:
类型 | 值范围 | 字节数 |
---|---|---|
Int8Array | -128~127 | 1 |
Uint8Array | 0~255 | 1 |
Uint8ClampedArray | 0~255 | 1 |
Int16Array | -32768~32767 | 2 |
Uint16Array | 0~65535 | 2 |
Int32Array | -2147483648~217483647 | 4 |
Uint32Array | 0~4294967295 | 4 |
Float32Array | 1.2×10-38~3.4×1038 | 4 |
Float64Array | 5.0×10-324~3.4×10308 | 8 |
BigInt64Array | -263~263-1 | 8 |
BigUInt64Array | 0~264-1 | 8 |
4 Buffer类
Buffer类是基于Uint8Array的,因此其值为0~255的整数数组。
// 创建一个长度为10的零填充缓冲区
let buf1 = Buffer.alloc(10);
console.log(buf1);
输出结果:<Buffer 00 00 00 00 00 00 00 00 00 00>
// 创建一个长度为10的填充0x1的缓冲区
let buf2 = Buffer.alloc(10, 1);
console.log(buf2);
输出结果: <Buffer 01 01 01 01 01 01 01 01 01 01>
// 创建一个长度为10的未初始化缓冲区,这比调用alloc()更快
// 但返回了缓冲区实例,可能包含旧数据,可以通过fill()或write()来覆盖旧值
let buf3 = Buffer.allocUnsafe(10);
console.log(buf3);
输出结果:<Buffer 00 00 00 00 00 00 00 00 00 00>
//创建包含[0x1,0x2,0x3]的缓冲区
const buf4 = Buffer.from([1, 2, 3]);
console.log(buf4);
输出结果:<Buffer 01 02 03>
//创建包含UTF-8字节的缓冲区[0x74、0xc3、0xa9、0x73、0x74]
const buf5 = Buffer.from("test");
console.log(buf5);
输出结果:<Buffer 74 65 73 74>
//创建一个包含Latin-1
const buf6 = Buffer.from("abc", "latin1")
console.log(buf6);
输出结果:<Buffer 61 62 63>
const buf4 = Buffer.from([1, 2, 3]);
//使用for循环迭代缓冲区中的数据
for (const i of buf4) {
console.log(i)
}
5 Buffer构造函数
Buffer作为构造函数,可以用new命令生成一个实例,它可以接受多种形式的参数。
//参数是整数,指定分配多少个字节内存
var hello = new Buffer(5);
//参数是数组,数组成员必须是整数值
var hello = new Buffer([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
console.log(hello.toString()); // hello
//参数是字符串(默认为utf8编码)
var hello = new Buffer("Hello");
console.log(hello.length) // 5
console.log(hello.toString()) // "Hello"
//参数是字符串(不省略编码)
var hello = new Buffer('Hello', 'utf8');
//参数是另一个Buffer实例,等同于拷贝后者
var hello1 = new Buffer('Hello');
var hello2 = new Buffer(hello1);
6 Buffer类的方法(函数)
6.1 Buffer.isEncoding()
Buffer.isEncoding():返回一个布尔值,表示Buffer实例是否为指定编码。
var hello = new Buffer(5);
console.log(Buffer.isEncoding('utf8')); // true
6.2 Buffer.isBuffer()
Buffer.isBuffer():接受一个对象作为参数,返回一个布尔值,表示该对象是否为Buffer实例。
var date = new Date();
console.log(Buffer.isBuffer(date)); // false
6.3 Buffer.byteLength()
Buffer.byteLength():返回字符串实际占据的字节长度,默认编码方式为utf8。
var hello = new Buffer([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
var len = Buffer.byteLength(hello);
console.log(len); // 5
6.4 Buffer.concat()
Buffer.concat():将一组Buffer对象合并为一个Buffer对象。
var i1 = new Buffer("Hello");
var i2 = new Buffer(" ");
var i3 = new Buffer("World");
var buf = Buffer.concat([i1, i2, i3]).toString();
console.log(buf); // Hello World
需要注意的是,如果Buffer.concat的参数数组只有一个成员,就直接返回该成员。如果有多个成员,就返回一个多个成员合并的新Buffer对象。
Buffer.concat方法还可以接受第二个参数,指定合并后Buffer对象的总长度。
var i1 = new Buffer("Hello");
var i2 = new Buffer(" ");
var i3 = new Buffer("World");
let buf = Buffer.concat([i1, i2, i3], 10).toString();
console.log(buf); // Hello Worl
7 实例属性 length
length:返回Buffer对象所占据的内存长度。注意,这个值与Buffer对象的内容无关。
var buf = new Buffer(1234);
console.log(buf.length); // 1234
buf.write("hello world", 0, "ascii");
console.log(buf.length); // 1234
上面代码中,不管写入什么内容,length属性总是返回Buffer对象的空间长度。如果想知道一个字符串所占据的字节长度,可以将其传入Buffer.byteLength方法。
length属性是可写的,但是这会导致未定义的行为,不建议使用。如果想修改Buffer对象的长度,建议使用slice方法返回一个新的Buffer对象。
8 实例方法
8.1 write()
write()可以向指定的Buffer对象写入数据。它的第一个参数是所写入的内容,第二个参数(可省略)是所写入的起始位置(默认从0开始),第三个参数(可省略)是编码方式,默认为utf8。
var buf = new Buffer(5);
buf.write('He');
buf.write('l', 2);
buf.write('lo', 3);
console.log(buf.toString()); // Hello
8.2 slice()
slice():返回一个按照指定位置、从原对象切割出来的Buffer实例。它的两个参数分别为切割的起始位置和终止位置。
var buf = new Buffer("abcd efg hijk lm");
var chunk = buf.slice(5, 9);
console.log(chunk.toString()); // efg
8.3 toString()
toString():将Buffer实例,按照指定编码(默认为utf8)转为字符串。
var hello = new Buffer("Hello");
console.log(hello.toString()); // Hello
toString()方法可以只返回指定位置内存的内容,它的第二个参数表示起始位置,第三个参数表示终止位置,两者都是从0开始计算。
var buf = new Buffer("abcd efgh i jk");
console.log(buf.toString("ascii", 5, 9)); // efgh
8.4 toJSON()
toJSON():将Buffer实例转为JSON对象。如果JSON.stringify()方法调用Buffer实例,默认会先调用toJSON方法。
var buf = new Buffer("test");
var json = JSON.stringify(buf);
var copy = new Buffer(JSON.parse(json));
console.log(copy); // <Buffer 74 65 73 74>