NodeJs Buffer

流是数据的集合(与数据、字符串类似),但是流的数据不能一次性获取到,数据也不会全部load到内存中,因此流非常适合大数据处理以及断断续续返回chunk的外部源。流的生产者与消费者之间的速度通常是不一致的,因此需要buffer来暂存一些数据。buffer大小通过highWaterMark参数指定,默认情况下是16Kb。

存储需要占用大量内存的数据

Buffer 对象占用的内存空间是不计算在 Node.js 进程内存空间限制上的,所以可以用来存储大对象,但是对象的大小还是有限制的。一般情况下32位系统大约是1G,64位系统大约是2G。

如何创建Buffer

除了流自动隐式创建Buffer之外,也可以手动创建Buffer,方式如下:

Buffer中存储的数据已确定

Buffer.from(obj) // obj支持的类型string, buffer, arrayBuffer, array, or array-like object

注意:Buffer.from不支持传入数字,如下所示:

Buffer.from(1234);

buffer.js:208

throw new errors.TypeError(

^

TypeError [ERR_INVALID_ARG_TYPE]: The “value” argument must not be of type number. Received type number

at Function.from (buffer.js:208:11)

若要传入数字可以采用传入数组的方式:

const buf = Buffer.from([1, 2, 3, 4]);

console.log(buf); // <Buffer 01 02 03 04>

但是这种方式存在一个问题,当存入不同的数值的时候buffer中记录的二进制数据会相同,如下所示:

const buf2 = Buffer.from([127, -1]);

console.log(buf2); // <Buffer 7f ff>

const buf3 = Buffer.from([127, 255]);

console.log(buf3); // <Buffer 7f ff>

console.log(buf3.equals(buf2)); // true

当要记录的一组数全部落在0到255(readUInt8来读取)这个范围, 或者全部落在-128到127(readInt8来读取)这个范围那么就没有问题,否则的话就强烈不推荐使用Buffer.from来保存一组数。因为不同的数字读取时应该调用不同的方法。

Buffer存储数据未确定

Buffer.alloc、Buffer.allocUnsafe、Buffer.allocUnsafeSlow

Buffer.alloc会用0值填充已分配的内存,所以相比后两者速度上要慢,但是也较为安全。当然也可以通过–zero-fill-buffers flag使allocUnsafe、allocUnsafeSlow在分配完内存后也进行0值填充。

node --zero-fill-buffers index.js

当分配的空间小于4KB的时候,allocUnsafe会直接从之前预分配的Buffer里面slice空间,因此速度比allocUnsafeSlow要快,当大于等于4KB的时候二者速度相差无异。

// 分配空间等于4KB

function createBuffer(fn, size) {

console.time(‘buf-’ + fn);

for (var i = 0; i < 100000; i++) {

Bufferfn;

}

console.timeEnd(‘buf-’ + fn);

}

createBuffer(‘alloc’, 4096);

createBuffer(‘allocUnsafe’, 4096);

createBuffer(‘allocUnsafeSlow’, 4096);

// 输出

buf-alloc: 294.002ms

buf-allocUnsafe: 224.072ms

buf-allocUnsafeSlow: 209.22ms

function createBuffer(fn, size) {

console.time(‘buf-’ + fn);

for (var i = 0; i < 100000; i++) {

Bufferfn;

}

console.timeEnd(‘buf-’ + fn);

}

createBuffer(‘alloc’, 4095);

createBuffer(‘allocUnsafe’, 4095);

createBuffer(‘allocUnsafeSlow’, 4095);

// 输出

buf-alloc: 296.965ms

buf-allocUnsafe: 135.877ms

buf-allocUnsafeSlow: 205.225ms

需要谨记一点:new Buffer(xxxx) 方式已经不推荐使用了

Buffer使用

buffer转字符串

const buf = Buffer.from(‘test’);

console.log(buf.toString(‘utf8’)); // test

console.log(buf.toString(‘utf8’, 0, 2)); // te

buffer转json

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);

console.log(buf.toJSON()); // { type: ‘Buffer’, data: [ 1, 2, 3, 4, 5 ] }

buffer裁剪,裁剪后返回的新的buffer与原buffer指向同一块内存

buf.slice([start[, end]])

start 起始位置

end 结束位置(不包含)

示例:

var buf1 = Buffer.from(‘test’);

var buf2 = buf1.slice(1, 3).fill(‘xx’);

console.log("buf2 content: " + buf2.toString()); // xx

console.log("buf1 content: " + buf1.toString()); // txxt

buffer拷贝,buffer与数组不同,buffer的长度一旦确定就不再变化,因此当拷贝的源buffer比目标buffer大时只会复制部分的值

buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])

示例:

var buf1 = Buffer.from(‘abcdefghijkl’);

var buf2 = Buffer.from(‘ABCDEF’);

buf1.copy(buf2, 1);

console.log(buf2.toString()); //Abcdef

buffer相等判断,比较的是二进制值

buf.equals(otherBuffer)

示例:

const buf1 = Buffer.from(‘ABC’);

const buf2 = Buffer.from(‘414243’, ‘hex’);

console.log(buf1.equals(buf2)); // true

除了equals之外,compare其实也可以用于判断是否相等(当结果为0则相等),不过compare更主要的作用是用于对数组内的buffer实例排序。

buffer是否包含特定值

buf.includes(value[, byteOffset][, encoding])

buf.indexOf(value[, byteOffset][, encoding])

示例:

const buf = Buffer.from(‘this is a buffer’);

console.log(buf.includes(‘this’)); // true

console.log(buf.indexOf(‘this’)); // 0

写入读取数值

写入方法:

位数固定且超过1个字节的: write{Double| Float | Int16 | Int32| UInt16 | UInt32 }{BE|LE}(value, offset)

位数不固定的: write{Int | UInt}{BE | LE}(value, offset, bytelength) //此方法提供了更灵活的位数表示数据(比如3位、5位)

位数固定是1个字节的: write{Int8 | Unit8}(value, offset)

读取方法:

位数固定且超过1个字节的: read{Double| Float | Int16 | Int32 | UInt16 | UInt32 }{BE|LE}(offset)

位数不固定的: read{Int | UInt}{BE | LE}(offset, byteLength)

位数固定是1个字节的: read{Int8 | Unit8}(offset)

Double、Float、Int16、Int32、UInt16、UInt32既确定了表征数字的位数,也确定了是否包含负数,因此定义了不同的数据范围。同时由于表征数字的位数都超过8位,无法用一个字节来表示,因此就涉及到了计算机的字节序区分(大端字节序与小端字节序)

关于大端小端的区别可以这么理解:数值的高位在buffer的起始位置的是大端,数值的低位buffer的起始位置则是小端

const buf = Buffer.allocUnsafe(2);

buf.writeInt16BE(256, 0)

console.log(buf); // <Buffer 01 00>

buf.writeInt16LE(256, 0)

console.log(buf); // <Buffer 00 01>

https://tool.lu/hexconvert/ 这里可以查看数值的不同进制之间的转换,如果是大端的话,则直接按顺序(0100)拼接16进制即可,如果是小端则需要调换一下顺序才是正确的表示方式。

buffer合并

Buffer.concat(list[, totalLength]) //totalLength不是必须的,如果不提供的话会为了计算totalLength会多一次遍历

const buf1 = Buffer.from(‘this is’);

const buf2 = Buffer.from(’ funny’);

console.log(Buffer.concat([buf1, buf2], buf1.length + buf2.length));

// <Buffer 74 68 69 73 20 69 73 20 66 75 6e 6e 79>

清空buffer

清空buffer数据最快的办法是buffer.fill(0)

buffer模块与Buffer的关系

Buffer是全局global上的一个引用,指向的其实是buffer.Buffer

const buffer = require(‘buffer’);

console.log(buffer.Buffer === Buffer); //true

buffer模块上还有其他一些属性和方法

const buffer = require(‘buffer’);

console.log(buffer);

{ Buffer:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值