当前位置: 首页 > 后端技术 > Node.js

NodeBuffer解读

时间:2023-04-03 12:46:09 Node.js

Buffer是什么?Buffer存在于全局对象之上,无需引入模块即可使用,可见其重要性。可以理解Buffer是在内存中开辟的一块区域,用于存放二进制数据。Buffer开辟的是堆外内存。Buffer的应用场景有哪些?flow怎么理解flow?流是数据的集合(类似于数据和字符串),但是流的数据不能一次性获取,也不会全部加载到内存中。因此,流非常适合大数据处理和间歇性地向外部源返回块。流的生产者和消费者之间的速度通常是不一致的,所以需要一个缓冲区来临时存储一些数据。缓冲区大小由highWaterMark参数指定,默认为16Kb。存储需要大量内存的数据Buffer对象占用的内存空间不计入N??ode.js进程的内存空间限制,所以可以用来存储大对象,但是对象的大小还是有限的。一般来说,32位系统1G左右,64位系统2G左右。如何创建Buffer除了流自动隐式创建Buffer外,还可以手动创建Buffer,如下:Buffer中存储的数据已经确定Buffer.from(obj)//Thetypesobj支持的有string,buffer,arrayBuffer,array,orarray-likeobject注意:Buffer.from不支持传入数字,如下:Buffer.from(1234);buffer.js:208thrownewerrors.TypeError(^TypeError[ERR_INVALID_ARG_TYPE]:The"value"argumentmustnotbeoftypenumber.ReceivedtypenumberatFunction.from(buffer.js:208:11)...如果要传入数字,可以传入一个array:constbuf=Buffer.from([1,2,3,4]);console.log(buf);//但是这个方法有个问题,当存储不同的值时,buffer中记录的二进制数据会是一样的,如下所示:constbuf2=Buffer.from([127,-1]);console.log(buf2);constbuf3=Buffer.from([127,255]);console.log(buf3);console.log(buf3.equals(buf2));//true当要记录的数字集合都在0到255范围内(readUInt8读取),或者都在-128到范围内127(readInt8读取),那就没问题了,否则强烈不建议使用Buffer.from来保存一组数字。因为读取不同的方法应该调用不同的数字。Buffer存储数据不确定Buffer.alloc、Buffer.allocUnsafe、Buffer.allocUnsafeSlowBuffer.alloc会将分配的内存填充为0,所以比后两者慢,但也更安全。当然你也可以使用--zero-fill-buffers标志让allocUnsafe和allocUnsafeSlow在分配内存后填充0值。node--zero-fill-buffersindex.js当分配的空间小于4KB时,allocUnsafe会直接从之前预分配的Buffer中分片空间,所以速度比allocUnsafeSlow快。当分配的空间大于或等于4KB时,两者的速度差别不大。//分配空间等于functioncreateBuffer(fn,size){console.time('buf-'+fn);对于(vari=0;i<100000;i++){Buffer[fn](size);}安慰。timeEnd('buf-'+fn);}createBuffer('alloc',4096);createBuffer('allocUnsafe',4096);createBuffer('allocUnsafeSlow',4096);//输出buf-alloc:294.002msbuf-allocUnsafe:224.072msbuf-allocUnsafeSlow:209.22msfunctioncreateBuffer(fn,size){console.time('buf-'+fn);对于(vari=0;i<100000;i++){Buffer[fn](size);}console.timeEnd('buf-'+fn);}createBuffer('alloc',4095);createBuffer('allocUnsafe',4095);createBuffer('allocUnsafeSlow',4095);//输出buf-alloc:296.965msbuf-allocUnsafe:135.877msbuf-allocUnsafeSlow:205.225ms需要注意一点:新的Buffer(xxxx)方法不再推荐使用Buffer使用buffer来转换字符串constbuf=Buffer.from('test');console.日志(buf.toString('utf8'));//testconsole.log(buf.toString('utf8',0,2));//tebuffer到jsonconstbuf=Buffer.from([0x1,0x2,0x3,0x4,0x5]);console.log(buf.toJSON());//{type:'Buffer',data:[1,2,3,4,5]}缓冲区裁剪,裁剪后返回的新缓冲区指向与原缓冲区相同的内存块buf.slice([start[,end]])start起始位置end结束位置(不包括)例子:varbuf1=Buffer.from('test');varbuf2=buf1.slice(1,3).fill('xx');console.log("buf2内容:"+buf2.toString());//xxconsole.log("buf1内容:"+buf1.toString());//txxtbuffer复制,buffer不同于数组,buffer的长度一旦确定,就不会改变,所以当复制的sourcebuffer大于targetbuffer时,只会复制部分值buf.copy(target[,targetStart[,sourceStart[,sourceEnd]]])示例:varbuf1=Buffer.from('abcdefghijkl');varbuf2=Buffer.from('ABCDEF');buf1.copy(buf2,1);console.log(buf2.toString());//abcdefbuffer相等判断,比较的是二进制值buf.equals(otherBuffer)例子:constbuf1=Buffer.from('ABC');constbuf2=Buffer.from('414243','hex');console.log(buf1.equals(buf2));//true除了equals之外,compare其实也可以用来判断是否相等(结果为0时相等),但是compare的主要作用是比较数组中的buffer实例进行排序缓冲区是否包含特定值buf.includes(value[,byteOffset][,encoding])buf.indexOf(value[,byteOffset][,encoding])示例:constbuf=Buffer.from('thisisabuffer');console.log(buf.includes('this'));//trueconsole.log(buf.indexOf('this'));//0写入读取值写入方法:write{Double|浮动|整数16|诠释32|单位16|UInt32}{BE|LE}(值,偏移量)写入{Int|UInt}{BE|LE}(value,offset,bytelength)//这个方法提供了更灵活的位数来表示数据(比如3位,5位)write{Int8|Unit8}(value,offset)读方法:write{Double|浮动|整数16|整数32|单位16|UInt32}{BE|LE}(偏移量)读取{Int||LE}(offset,byteLength)read{Int8|Unit8}(offset)Double,Float,Int16,Int32,UInt16,UInt32不仅要判断代表数字的位数,还要判断是否包含负数,所以定义不同的数据范围。同时,由于表示数字的位数超过了8位,不能用一个字节来表示,所以涉及到计算机的字节序区分(big-endian字节序和little-endian字节序)。big-endian和small-endian的区别可以这样理解:value的高位在buffer的起始位置,value的低位起始位置是littleendian。constbuf=Buffer.allocUnsafe(2);buf.writeInt16BE(256,0)console.log(buf);//<缓冲区0100>buf.writeInt16LE(256,0)console.log(buf);//https://tool.lu/hexconvert/这里可以查看value的不同进度对于系统间的转换,如果是bigendian,可以直接按顺序拼接十六进制(0100),如果是小端,则需要更改顺序才能正确表示。BuffermergeBuffer.concat(list[,totalLength])//totalLength不是必须的,如果没有提供,会再次遍历计算totalLengthconstbuf1=Buffer.from('thisis');constbuf2=Buffer.from('funny');console.log(Buffer.concat([buf1,buf2],buf1.length+buf2.length));//<缓冲区746869732069732066756e6e79>Emptybuffer清除buffer数据最快的方法是buffer.fill(0)buffer模块和Buffer的关系Buffer是global全局上的引用,指向buffer.Bufferconstbuffer=require('buffer');console.log(buffer.Buffer===Buffer);//truebuffer模块上还有其他属性和方法constbuffer=require('buffer');console.log(buffer);{Buffer:{[Function:Buffer]poolSize:8192,from:[Function:from],alloc:[函数:alloc],allocUnsafe:[函数:allocUnsafe],allocUnsafeSlow:[函数:allocUnsafeSlow],isBuffer:[函数:isBuffer],比较:[函数:比较],isEncoding:[函数:isEncoding],concat:[函数:concat],byteLength:[函数:byteLength],[Symbol(node.isEncoding)]:[Function:isEncoding]},slowbuffer:[函数:slowbuffer],thressCode:[function:transcode],istect_max_bytes:50,kmaxlength:2147483647,kstringmaxlength:kstringmaxlength:1073741799,startantMAX_LENGTH表示创建新缓冲区时内存大小的最大值。当超过限制值时,会报错32。在机器上是(2^30)-1(~1GB),在64位机器上是(2^31)-1(~2GB)缓冲区释放我们无法手动GC缓冲区实例,只能靠V8要做到这一点,我们唯一能做的就是去掉对buffer实例的引用参考http://cenalulu.github.io/lin...http://www.ruanyifeng.com/blo...https//medium.freecodecamp.o...https://www.barretlee.com/blo...https://medium.freecodecamp.o...http://www.runoob.com/nodejs/...