[AY-Node.js]写给自己的NodeJs-buffer讲解[4]

来源:互联网 时间:1970-01-01

好了,到现在开始,我们还是用NotePad++来写吧,最后我们再用webstorm

buffer也就类似 C#的string,但也不是

新建一个bufferdemo.js文件

1. Buffer介绍

在Node.js中,Buffer类是随Node内核一起发布的核心库。Buffer库为Node.js带来了一种存储原始数据的方法,可以让Nodejs处理二进制数据,每当需要在Nodejs中处理I/O操作中移动的数据时,就有可能使用Buffer库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

Buffer 和 Javascript 字符串对象之间的转换需要显式地调用编码方法来完成。以下是几种不同的字符串编码:

‘ascii’ – 仅用于 7 位 ASCII 字符。这种编码方法非常快,并且会丢弃高位数据。

‘utf8′ – 多字节编码的 Unicode 字符。许多网页和其他文件格式使用 UTF-8。

‘ucs2′ – 两个字节,以小尾字节序(little-endian)编码的 Unicode 字符。它只能对 BMP(基本多文种平面,U+0000 – U+FFFF) 范围内的字符编码。

‘base64′ – Base64 字符串编码。

‘binary’ – 一种将原始二进制数据转换成字符串的编码方式,仅使用每个字符的前 8 位。这种编码方法已经过时,应当尽可能地使用 Buffer 对象。Node 的后续版本将会删除这种编码。

Buffer官方文档:http://nodejs.org/api/buffer.html

2. Buffer的基本使用

Buffer的基本使用,主要就是API所提供的操作,主要包括3个部分 创建Buffer类、读Buffer、写Buffer。由于基本操作在官方文档中详细的使用介绍,我只是简单列举一下。

demo开始

创建一个长度为0的buffer实例

长度为10的buffer实例

创建一个数组

字符编码

Buffer辅助方法

1.编码检查

2.Buffer检查,很多时候我们需要判断数据的类型,对应后续的操作

3.字符串的字节长度,由于字符串编码不同,所以字符串长度和字节长度有时是不一样的。比如,1个中文字符是3个字节,通过utf-8编码输出就是4个中文字符,占12个字节

特别注意,js文件的代码最好是utf-8格式编码,然后中文就可以用了

4.Buffer的连接,用于连接Buffer的数组。我们可以手动分配Buffer对象合并后的Buffer空间大小,如果Buffer空间不够了,则数据会被截断

多了,就乱码

5.buffer比较

6. 读写buffer

通过write写入字符,write后面的参数,默认是0,也可以指定偏移量,继续写。toString可以输出

Node.js的节点的缓冲区,根据读写整数的范围,提供了不同宽度的支持,使从1到8个字节(8位、16位、32位)的整数、浮点数(float)、双精度浮点数(double)可以被访问,分别对应不同的writeXXX()函数,使用方法与buf.write()类似

buf.write(string[, offset][, length][, encoding])buf.writeUIntLE(value, offset, byteLength[, noAssert])buf.writeUIntBE(value, offset, byteLength[, noAssert])buf.writeIntLE(value, offset, byteLength[, noAssert])buf.writeIntBE(value, offset, byteLength[, noAssert])buf.writeUInt8(value, offset[, noAssert])buf.writeUInt16LE(value, offset[, noAssert])buf.writeUInt16BE(value, offset[, noAssert])buf.writeUInt32LE(value, offset[, noAssert])buf.writeUInt32BE(value, offset[, noAssert])buf.writeInt8(value, offset[, noAssert])buf.writeInt16LE(value, offset[, noAssert])buf.writeInt16BE(value, offset[, noAssert])buf.writeInt32LE(value, offset[, noAssert])buf.writeInt32BE(value, offset[, noAssert])buf.writeFloatLE(value, offset[, noAssert])buf.writeFloatBE(value, offset[, noAssert])buf.writeDoubleLE(value, offset[, noAssert])buf.writeDoubleBE(value, offset[, noAssert])

另外,关于Buffer写入操作,还有一些Buffer类的原型函数可以操作

copy复制操作

// 新建两个Buffer实例

var buf1 = new Buffer(26);

var buf2 = new Buffer(26);

// 分别向2个实例中写入数据

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

buf1[i] = i + 97; // 97是ASCII的a

buf2[i] = 50; // 50是ASCII的2

}

// 把buf1的内存复制给buf2

buf1.copy(buf2, 5, 0, 10); // 从buf2的第5个字节位置开始插入,复制buf1的从0-10字节的数据到buf2中

console.log(buf2.toString('ascii', 0, 25)); // 输入buf2的0-25字节

> 22222abcdefghij2222222222

Fill方法

// 新建Buffer实例,长度20节节

var buf = new Buffer(20);

// 向Buffer中填充数据

buf.fill("h");

console.log(buf)

> <Buffer 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68>

console.log("buf:"+buf.toString())

> buf:hhhhhhhhhhhhhhhhhhhh

// 清空Buffer中的数据

buf.fill();

console.log("buf:"+buf.toString())

> buf:

slice裁剪,同一个引用,不同的切断

Buffer裁剪,buf.slice([start][, end])。 返回一个新的缓冲区,它和旧缓冲区指向同一块内存,但是从索引 start 到 end 的位置剪裁。

var buf1 = new Buffer(26);

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

buf1[i] = i + 97;

}

// 从剪切buf1中的0-3的位置的字节,新生成的buf2是buf1的一个切片。

var buf2 = buf1.slice(0, 3);

console.log(buf2.toString('ascii', 0, buf2.length));

> abc

// 当修改buf1时,buf2同时也会发生改变

buf1[0] = 33;

console.log(buf2.toString('ascii', 0, buf2.length));

> !bc

读取buffer

一个是toString方法

一个是其他的方法

前面说过了,utf-8中,3个字节算一个中文字符

所以230,149,176代表 “数” 230,141,174代表“据”

toString默认调用,默认utf-8,下面是toJSON()方法

性能测试

下面我们创建2个Buffer实例,第一个是以4k为空间,第二个以4.001k为空间,循环创建10万次

多Buffer还是单一Buffer

当我们需要对数据进行缓存时,创建多个小的Buffer实例好,还是创建一个大的Buffer实例好?比如我们要创建1万个长度在1-2048之间不等的字符串

var max = 2048; //最大长度

var time = 10*1000; //循环1万次

// 根据长度创建字符串

function getString(size){

var ret = ""

for(var i=0;i<size;i++) ret += "a";

return ret;

}

// 生成字符串数组,1万条记录

var arr1=[];

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

var size = Math.ceil(Math.random()*max)

arr1.push(getString(size));

}

//console.log(arr1);

// 创建1万个小Buffer实例

console.time('test3');

var arr_3 = [];

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

arr_3.push(new Buffer(arr1[i]));

}

console.timeEnd('test3');

> test3: 217ms

// 创建一个大实例,和一个offset数组用于读取数据。

console.time('test4');

var buf = new Buffer(time*max);

var offset=0;

var arr_4=[];

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

arr_4[i]=offset;

buf.write(arr1[i],offset,arr1[i].length);

offset=offset+arr1[i].length;

}

console.timeEnd('test4');

> test4: 12ms

读取索引为2的数据。

console.log("src:[2]="+arr1[2]);

console.log("test3:[2]="+arr_3[2].toString());

console.log("test4:[2]="+buf.toString('utf-8',arr_4[2],arr_4[3]));

对于这类的需求来说,提前生成一个大的Buffer实例进行存储,要比每次生成小的Buffer实例高效的多,能提升一个数量级的计算效率。所以,理解并用好Buffer是非常重要的!!

string VS Buffer

有了Buffer我们是否需求把所有String的连接,都换成Buffer的连接?那么我们就需要测试一下,String和Buffer做字符串连接时,哪个更快一点?

下面我们进行字符串连接,循环30万次。

//测试三,Buffer VS string

var time = 300*1000;

var txt = "aaa"

var str = "";

console.time('test5')

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

str += txt;

}

console.timeEnd('test5')

> test5: 24ms

console.time('test6')

var buf = new Buffer(time * txt.length)

var offset = 0;

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

var end = offset + txt.length;

buf.write(txt,offset,end);

offset=end;

}

console.timeEnd('test6')

> test6: 85ms

从测试结果,我们可以明显的看到,String对字符串的连接操作,要远快于Buffer的连接操作。所以我们在保存字符串的时候,该用string还是要用buffer。那么只有在保存非utf-8的字符串以及二进制数据的情况,我们才用Buffer。

本文参考地址:http://www.111cn.net/wy/js-ajax/80970.htm

======================================== AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢===============

推荐您阅读更多有关于“nodejs,”的文章


相关阅读:
Top