深入浅出node读书笔记(四)
本篇文章介绍Buffer相关的概念。前端JavaScript对字符串的操作相对友好,有一系列比较好用的api来操作字符串。但是如果把js挪到后端,这些api明显不够,因为node在处理的时候需要大量处理一些二进制文件,前端那些api是远远不足的,于是buffer对象应运而生。
首先,buffer模块在node启动的时候已经自动加载进去了,无需require()进去。
(1)buffer对象类似数组,它的元素是16进制的两位数,都在0~255之间。用.length属性能够得到buffer的长度。我们在把字符串转为buffer对象之后,是能够设置buffer[]里面的值的,如果设置范围不在0~255之间,node会自动+(-)256来规范数值,如果是小数则舍弃小数部分。
(2)buffer的内存分配。
该分配取决于buffer对象的大小,该大小以8kb来界定,小于8k的为小buffer,这也是操作系统的slab动态内存分配机制:slab是一块已经申请好的内存块,如果是小buffer对象,则会把对象分到一个slab中,如果slab没满,就继续放,如果slab剩下的空间不足以放一个buffer对象,则会启用下一个slab,之前的slab剩余被浪费掉。如果是一个超过8kb的大buffer对象,操作系统将会分配一个slowBuffer对象作为slab来被大buffer对象独立占据。
(3)buffer转换:
字符串转buffer
var str='我是谁'; var str2='abcde'; var buf=new Buffer(str,'utf-8'); //buffer对象可能是多次写入 buf.write(str2);
buffer转字符串:转化过程中因为截取buffer原因会出现乱码。
buf.toString();
(4)buffer的拼接:
var fs = require('fs'); var rs = fs.createReadStream('test.md'); var data = ''; rs.on("data", function (chunk){ data += chunk; //此处隐藏data与chunk的toString()操作 }); rs.on("end", function () { console.log(data); });
在外语中这样操作没问题,但如果是中文,每个汉字转化为三个buffer二进制值,就会因截取的任意性而在tostring的过程中转化为乱码,这也就是乱码产生的原因。
(5)解决乱码的方法:此处只介绍一种较通用的方法:把一些小的buffer对象拼接成一个buffer对象,一次性转码。
var chunks = []; var size = 0; res.on('data', function (chunk) { chunks.push(chunk); size += chunk.length; }); res.on('end', function () { var buf = Buffer.concat(chunks, size); var str = iconv.decode(buf, 'utf8'); console.log(str); });
chunks数组每次把读取的buf对象chunk加入到数组中,然后记录下总length。然后通过Buffer.concat(chunks,size)来把小的buf对象拼接成一个大的,然后转码即不会出现乱码。
(6)buffer与性能:静态内容转为为buffer对象形式在网络中传输速度较快,效率高。
在文件读取的时候,我们会设置一些属性,其中有一个highWaterMark属性,该属性决定读取文件的速度,表示每次从文件中读出多少字节。
fs.createReadStream()的工作方式是在内中一Buffer,后在fs.read()读取文件时候将字节复制到Buffer中。完成一次读取操作,从这个Buffer中通过slice()方法取出一部分数据作为一个小Buffer对像,通过data事件传递给调用方。如果Buffer用完,重新申请一个,没用完则接着用。