NodeJS模块Buffer原理及使用方法解析
Buffer作为nodejs中重要的概念和功能,为开发者提供了操作二进制的能力。本文记录了几个问题,来加深对Buffer的理解和使用:
- 认识缓冲器
- 如何申请堆外内存
- 如何计算字节长度
- 如何计算字节长度
- 如何转换字符编码
- 理解共享内存与拷贝内存
认识Buffer(缓冲器)
Buffer是nodejs核心API,它提供我们处理二进制数据流的功能。Buffer的使用和ES2017的Uint8Array非常相似,但由于node的特性,专门提供了更深入的api。
Uint8Array的字面意思就是:8位无符号整型数组。一个字节是8bit,而字节的表示也是由两个16进制(4bit)的数字组成的。
constbuf=Buffer.alloc(1);
console.log(buf);//output:
如何申请堆外内存
Buffer可以跳出nodejs对堆内内存大小的限制。nodejs12提供了4种api来申请堆外内存:
- Buffer.from()
- Buffer.alloc(size[,fill[,encoding]])
- Buffer.allocUnsafe(size)
- Buffer.allocUnsafeSlow(size)
Buffer.allocvsBuffer.allocUnsafe
在申请内存时,可能这片内存之前存储过其他数据。如果不清除原数据,那么会有数据泄漏的安全风险;如果清除原数据,速度上会慢一些。具体用哪种方式,根据实际情况定。
- Buffer.alloc:申请指定大小的内存,并且清除原数据,默认填充0
- Buffer.allocUnsafe:申请指定大小内存,但不清除原数据,速度更快
根据提供的api,可以手动实现一个alloc:
functionpollifyAlloc(size,fill=0,encoding="utf8"){ constbuf=Buffer.allocUnsafe(size); buf.fill(fill,0,size,encoding); returnbuf; }
Buffer.allocUnsafevsBuffer.allocUnsafeSlow
从命名上可以直接看出效果,Buffer.allocUnsafeSlow更慢。因为当使用Buffer.allocUnsafe创建新的Buffer实例时,如果要分配的内存小于4KB,则会从一个预分配的Buffer切割出来。这可以避免垃圾回收机制因创建太多独立的Buffer而过度使用。
这种方式通过消除跟踪和清理的需要来改进性能和内存使用。
如何计算字节长度
利用Buffer,可以获得数据的真实所占字节。例如一个汉字,它的字符长度是1。但由于是utf8编码的汉字,所以占用3个字节。
直接利用Buffer.byteLength()可以获得字符串指定编码的字节长度:
conststr="本文原文地址:xxoo521.com";
console.log(Buffer.byteLength(str,"utf8"));//output:31
console.log(str.length);//output:19
也可以直接访问Buffer实例的length属性(不推荐):
console.log(Buffer.from(str,"utf8").length);//output:31
如何转换字符编码
Nodejs当前支持的编码格式有:ascii、utf8、utf16le、ucs2、base64、latin1、binary、hex。其他编码需要借助三方库来完成。
下面,是用Buffer.from()和buf.toString()来封装的nodejs平台的编码转换函数:
functiontrans(str,from="utf8",to="utf8"){ constbuf=Buffer.from(str,from); returnbuf.toString(to); } //output:5Y6f5paH5Zyw5Z2AOiB4eG9vNTIxLmNvbQ== console.log(trans("原文地址:xxoo521.com","utf8","base64"));
共享内存与拷贝内存
在生成Buffer实例,操作二进制数据的时候,千万要注意接口是基于共享内存,还是基于拷贝底层内存。
例如对于生成Buffer实例的from(),不同类型的参数,nodejs底层的行为是不同的。
为了更形象地解释,请看下面两段代码。
代码1:
constbuf1=Buffer.from("buffer");
constbuf2=Buffer.from(buf1);//拷贝参数中buffer的数据到新的实例
buf1[0]++;console.log(buf1.toString());//output:cuffer
console.log(buf2.toString());//output:buffer
代码2:
constarr=newUint8Array(1);
arr[0]=97;constbuf1=Buffer.from(arr.buffer);
console.log(buf1.toString());//output:aarr[0]=98;
console.log(buf1.toString());//output:b
在第二段代码中,传入Buffer.from的参数类型是arrayBuffer。因此Buffer.from仅仅是创建视图,而不是拷贝底层内存。buf1和arr的内存是共享的。
在操作Buffer的过程中,需要特别注意共享和拷贝的区别,发生错误比较难排查。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。