Node -- 理解Buffer
来源:互联网 发布:微商推广软件 编辑:程序博客网 时间:2024/06/05 10:46
在Node中,应用需要处理网络协议、操作数据库、处理图片、接收上传文件等,在网络流和文件的操作中,还需要处理大量二进制数据。于是Buffer对象应运而生了。
Buffer结构
Buffer是一个像Array的对象,但是主要用来操作字节。
模块结构
Buffer是一个典型的JavaScript和C++结合的模块,它将性能相关部分用C++实现,将非性能部分用JS实现。
由于Buffer太过常见了,Node在进程启动时就已经加载了它,并将其放在全局对象上,所以在使用Buffer的时候,无须通过require就可以直接使用。
Buffer对象
Buffer对象类似于数组,它的元素为16进制的两位数,即0-255。
中文字在UTF-8编码下占用3个元素,字母和半角字符占用一个元素。
可以访问Buffer对象的length属性得到长度,也可以通过下标访问元素。
构造对象:
var buf = new Buffer(100); console.log(buf.length); // => 100
这些都和Array很像对吧~
上述代码分配了一个100字节的Buffer对象,它的元素值是一个0-255的随机值。
但是如果我们给Buffer[n]分配的不是0-255的整数或者是小数的时候回怎样呢?
如果给元素的赋值小于0,就会逐次+256,直到得到一个0-255的整数。如果大于255就逐次-256。如果是小数,就直接舍弃小数部分。(喵)
Buffer内存分配
Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存申请的。
也就是,Node在内存上应用的是在C++层面申请内存,在JS中分配内存的策略。
为了高效的使用申请来的内存,Node采用了slab分配机制。slab是一种动态内存管理机制。
简单而言,slab就是一块申请好的固定大小的内存区域,它有如下3种状态。
1、full:完全分配
2、partial:部分分配
3、empty:没有被分配
Node以8KB为界限来区分Buffer是大对象还是小对象。这个8KB的值也就是一个slab的大小,在JS层面,以它为单位单元来进行内存的分配。
分配小Buffer对象
使用局部变量pool作为中间处理对象。
利用pool的used属性记录使用了slab多少个字节。
再次创建Buffer的时候,回判断当前slab的剩余空间是否足够,不够的话就会构造新的slab,那么原来slab中剩余的空间将被浪费。
分配大Buffer对象
如果需要超过8KB的Buffer对象,将回直接分配一个SlowBuffer对象作为slab单元,这个slab单元将会被这个大Buffer对象独占。
总结:真正的内存是在Node的C++层面提供的,JS层面只是使用它。
Buffer的转换
支持的编码类型:
ASCIIUTF-8UTF-16LE/UCS-2Base64BinaryHex
字符串转Buffer
通过构造函数完成:
new Buffer(str, [encoding]);// encoding默认为UTF-8
一个Buffer对象可以存储不同编码类型的字符串转码的值。
buf.write(string, [offset], [length], [encoding])
Buffer转字符串
buf.toString([encoding], [start], [end])
Buffer不支持的编码类型
检测是否支持转换某个编码格式:
Buffer.isEncoding(encoding)
很遗憾,在中国常用的GBK,GB2312和BIG-5编码都不支持。(啊哦)
Buffer的拼接
读取文件:
var fs = require('fs');var rs = fs.createReadStream('test.md');var data = '';rs.on("data", function (chunk){ data += chunk; });rs.on("end", function () { console.log(data);});
这里的chunk对象就是Buffer对象。
但是,一旦输入流中有宽字节编码时,问题就会暴露出来——会出现乱码。
潜藏的问题来源于:data += chunk;
这段话等价于:data = data.toString() + chunk.toString();
对于宽字节的中文,就会出现问题
乱码是如何产生的
原因就是,中文字在UTF-8编码下占用3个字节,当一个中文字正好被Buffer对象截断的时候,就会出现乱码。
setEncoding & string_decoder
readable.setEncoding(encoding)
var rs = fs.createReadStream('test.md', { highWaterMark: 11});rs.setEncoding('utf8');
这样就可以消除乱码。
远离就是通过内部的decoder对象,将中文字的3个字符凑在一起。
它并不是万能的,目前只能处理UTF-8、Base64、UCS-2/UTF-16LE这3种编码。
正确拼接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);});
使用一个数组存储所有Buffer片段并记录总长度,然后调用Buffer.concat()
合并它们。
下面是Buffer.concat源码:
Buffer与性能
在应用中,我们通常会操作字符串,但是数据一旦在网络中传输,都需要转化为Buffer。
通过预先转换静态内容为Buffer对象,可以有效的减少CPU的重复使用,节省服务器资源。在Node构建的Web应用中,可以选择将页面中的动态内容和静态内容分离,静态内容部分可以通过预先转换为Buffer的方式,使性能得到提升。
- Node -- 理解Buffer
- Node.js——理解Buffer
- node buffer
- Node----Buffer
- node buffer
- 理解Buffer
- node.js Buffer模块
- Node.js Buffer使用方法
- Node.js8 Buffer对象
- Node.js 缓冲区 Buffer
- Node.js Buffer(缓冲区)
- Node.js Buffer学以致用
- Node.js Buffer(缓冲区)
- Node.js Buffer(缓冲区)
- Node——Buffer
- Node.js Buffer(缓冲区)
- Node.js Buffer
- Node.js buffer
- 数据挖掘经典算法--朴素贝叶斯分类
- 关于The MVP
- Trafodion Troubleshooting-current onlineEpoch is less than new onlineEpoch
- jackson序列化json报错java.lang.StackOverflowError
- 利用vmware在自己的个人电脑上面搭建虚拟linux服务器
- Node -- 理解Buffer
- 常见C++面试题1
- 数据结构复习——队列解决报数问题
- 美团CODEM 数码
- 二维数组复制到另一个二维数组
- 迈向成功的关键在于执行(摘自李开复博士的《做最好的自己》)
- Theme主题大全
- 庆祝六一
- Debian 8 Server搭建Postfix+Dovecot邮件服务器