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

Buffer_0

时间:2023-04-03 11:09:11 Node.js

节点核心模块学习Buffer什么是Buffer?在ES6引入TypeArray之前,JS没有读取和操作二进制数据流的机制。Buffer是作为NodeAPI引入的,目的是为了兼容TCP网络流、文件流等。目前ES6中有TypeArray,Buffer类以更优化的方式实现了Unit8ArrayAPI,更适合Node操作。简而言之,Buffer用于操作二进制数据,位于全局变量中,无需导入即可使用。Buffer实例类似于整数数组。缓冲区的大小在创建时就确定了,不能调整。内存由C++分配,由JS分配。Buffer类的实例类似于整数数组,但对应于V8堆之外的固定大小的原始内存分配。Buffer的大小在创建时确定,不能更改....读取或操作二进制数据流的机制。Buffer类是作为Node.jsAPI的一部分引入的,可以在TCP流和文件系统操作等上下文中与八位字节流进行交互。Buffercache区,计算机的读取速度与处理速度不匹配。当读取速度高于处理速度时,会开辟一段内存区域存放待处理的数据。这段内存称为缓冲区。实例化Buffer在v6.0之前创建Buffer对象,直接使用newBuffer()构造函数创建对象实例,但是Buffer对内存的权限操作比较大,可以直接抓取一些敏感信息,存在安全隐患。以后的版本,用下面的函数例子画一个Buffer:Buffer.from()Buffer.alloc()Buffer.allocUnsafe()函数参数返回值fromarryBuffer包含数组的字节副本,数组中的每一项代表一个8-bit字节数,所以取值在0--255以内,否则frombuffer从缓冲区fromarrayBuffer[,byteOffet,[,length]]和arrayBuffer共享内存Bufferfromstring[,encoding]stringinitializedBufferallocsize[,fill[encoding]]指定大小的Buffer实例,省略fill,默认用0填充allocUnsafesize指定大小的buffer。它未初始化,可能包含敏感信息。分配给allocUnsafe的内存没有初始化,也就是归零,内存速度快。但是,它可能包含旧数据,如果不覆盖这些数据,可能会发生内存泄漏。该编码支持以下编码:utfasciibase64binaryutf16lehex读写缓冲区buffer.write(string[offset,[length]][,encoding])string-要写入缓冲区的字符串;offset-开始写入的位置,默认0;length-写入字节,默认buf.lengthencoding-编码,默认utf8。返回值:int:写入的实际大小,空间不够保存,只写入一部分。buffer.toString([endcoding[,start=0[,end=buffer.length]]])解码指定缓冲区中的数据,返回一个endcoding格式的字符串。letbuf=Buffer.alloc(10);//分配10字节空间console.log(buf)//不填,填0letlen=buf.write('thisisabuffer');//16bytesconsole.log(buf)//console.log(len)//10//上面的代码和下面一样letbuffer=Buffer.from('thisisabuffer'.substring(0,10))console.log(buffer)//console.log(buffer.length)//10letbuf2=Buffer.alloc(8,10);//分配8字节内存,填充10console.log(buf2)//letsize=buf2.write('thisabuffer',2,2);//从索引2开始写入,写入2字节数据console.log(buf2)//console.log(size)//2console.log(buf.toString('utf16le',2,8));//扶椠?console.log(buf.toString('base64',2,8));//aXMgaXMgconsole.log(buf.toString('ascii',2,8));//isconsole.log(buf.toString('utf8',2,8));//isconsole.log(buf.toString('hex',2,8));//697320697320填充buffer.fill(value[,offset=0[,end=buffer.length]][,endcoding])value可以是Buffer,String,Intconstbuf1=Buffer.alloc(10).fill('abcd')//空间足够,循环填充console.log(buf1.toString())//abcdabcdab循环填充,知道空间满了constbuf2=Buffer.alloc(3).fill('abcdef');//空间不够,truncateconsole.log(buf2.toString());//abcconstbuf3=Buffer.alloc(10).fill('abc',3);//从索引3开始填充console.log(buf3);//console.log(buf3.toString());//abcabcabcaconstbuf4=Buffer.alloc(10).fill('abc',3,7);//从索引3填充到索引7console.log(buf4);//console.log(buf4.toString());//abcaletbuffer=Buffer.alloc(10).fill('abcd')console.log(buf4.toString())buffer=Buffer.alloc(10).fill(34)//改变原来的bufferconsole.log(buffer.toString())buffercomparebuffer.equals(buffer)比较两个buffer的数据是否相同。//示例1:相同的编码,相同的内容varbuf1=Buffer.from('A');varbuf2=Buffer.from('A');console.log(buf1.equals(buf2));//true//示例2:代码相同但内容不同varbuf3=Buffer.from('A');varbuf4=Buffer.from('B');console.log(buf3.equals(buf4));//false//例3:编码不同,内容相同varbuf5=Buffer.from('ABC');//varbuf6=Buffer.from('414243','hex');//varbuf7=Buffer.from('414243','utf16le');//console.log(buf5.equals(buf6));//trueconsole.log(buf7.equals(buf6));//falsebuf.compare(target[,targetStart[,targetEnd[,sourceStart[,sourceEnd]]]])compare可以指定比较的范围,返回一个数字。constbuf1=Buffer.from('ABC');constbuf2=Buffer.from('BCD');constbuf3=Buffer.from('ABCD');console.log(buf1.compare(buf1));//0console.log(buf1.compare(buf2));//-1console.log(buf1.compare(buf3));//-1console.log(buf2.compare(buf1));//1console.log(buf2.compare(buf3));//1//ABCBCDABCDconsole.log([buf1,buf2,buf3].sort(Buffer.compare));//[,,]ABCABCDBCDarr.sort(Buffer.compare)--buffer数组排序,按位比较,第一位能比较出结果,就确定了。constbuf1=Buffer.from('81234');constbuf2=Buffer.from('80234');constarr=[buf1,buf2];console.log(arr);//[<缓冲区3831323334>,]console.log(arr.sort(Buffer.compare));//[,]first,38=38,顺序取不到,第二位,30<31,buf2在前。检查bufferBufferBuffer.isBuffer(object)计算分配内存Buffer.byteLength(string,encoding='utf8')buffersizebuffer.lengthconsole.log(Buffer.byteLength('??'))//6需要6字节存储两个??letbuffer=Buffer.alloc(10).fill('?',4)//从索引4开始保存,正好够保存2?console.log(buffer.length)//10为buffer分配的内存spaceconsole.log('??'.length)//2个字符串长度console.log(buffer.toString())//'??'console.log(buffer.toString().length)//6个单位是bytesconsole.log(Buffer.byteLength('??'))//6需要6个字节来存储两个?letbuffer2=Buffer.alloc(10).fill('?',5)//从索引5开始保存,正好够省2个?还需要1个字节的空间console.log(buffer2.toString())//'??'有乱码console.log(buffer2.toString().length)//7个buffer连接Buffer.concat(bufferList[,totalLength])totalLength是所有bufferList元素的长度之和。totalLength>实际累计长度,补0;totalLength<实际累计长度,后者丢弃。//按照上面的代码letbuf3=Buffer.concat(arr,4);console.log(buf3);//丢弃四位letbuf4=Buffer.concat(arr,12);console.log(buf4);//0补两位复制bufSource.copy(bufTarget[,targetStart[,ssourceStart[,sourceEnd]]])copybufSourcesourceStart--sourceEnd-1字节存储在bufTarget的目标位置。返回值int:实际存储的字节数。目标缓冲区空间不够,复制源会被暂存。constbuf1=Buffer.alloc(10);//分配10字节空间constbuf2=Buffer.from('copyFunction');console.log('buf1beforecopying',buf1);//buf1beforecopyingconsole.log('buf2beforecopying',buf2);//buf2beforecopyingletresult=buf2.copy(buf1,4,1,5);//复制buf11--5个字节到buf2的第4个索引位置开始存储,用6个字节存储4个字节的数据,空间够用。console.log('buf1aftercopying',buf1);//buf1aftercopyingconsole.log(buf1.toString());//opyFconsole.log('copyAfterbuf2',buf2);//复制buf2后console.log(buf2.toString());//copyFunctionconsole.log('复制结果后',result);//4Interceptbuf.slice([start=0[,end=buf.length]])从buf中截取一部分组成新的buffer,两者内存共享,所以修改的时候会影响到各自其他。letbuf1=Buffer.alloc(5).fill('abcd')letbuf2=buf1.slice()console.log(buf2.toString())//abcdaletbuf3=buf1.slice(2,4)console.log(buf3)//cdconsole.log(buf3.toString())//cd//测试共享内存console.log(buf3[0]='100')//100修改buf3的第一个值为d,返回Modifiedvalueconsole.log(buf3[0].toString())//100console.log(buf3)//console.log(buf3.toString())//dd修改console.log(buf1)//console.log(buf1.toString())//abddbuf1也修改为searchforbuf.indexOf(value,byteOffset=0)从buf的byteOffset位置开始查找value,找到一个值,返回它的索引,否则返回-1。值可以是String、Int、Buffer。constbuf2=Buffer.from('copyFunction');让result=buf2.indexOf('c',3,'utf8');让result2=buf2.indexOf('c');让result3=buf2.indexOf('C');console.log(result);//7indexofthefirstcafterindex3console.log(result2);//0firstcconsole.log(result3);//-1buf2.indexOf(Buffer.from('copy'),2,'utf8');//-1buf2.indexOf(9,4);//-1letbuffer=Buffer.alloc(10).fill('abcd');console.log(buffer.toString());//abcdabcdab//递归查找所有bufferletindexes=[];//这里是存放找到的下标函数的keyrecursiveIndexOf(buffer,char,start){if(start<0){开始=0;}if(start>buffer.length-1){return-1;}//起始下标大于缓冲区最大下标,返回-1,也是递归出口letindex=buffer.indexOf(char,start);if(index!==-1){indexes.push(index);递归索引(缓冲区、字符、索引+1);}returnindexes;}letresult=recuisiveIndexOf(buffer,'a',0);console.log(result);//[0,4,8]buffertoStringandObjectbuf.toString([encoding=utf8[,start=0[,end=buf.length]]]),buf.toJSON()toJSON返回一个对象{type:'Buffer',data:[]}data是buffer的值。letbuffer=Buffer.alloc(10).fill('abcd');console.log(buffer.toString())//abcdconsole.log(buffer.toJSON())//{type:'Buffer',data:[97,98,99,100,97,98,99,100,97,98]}console.log(Object.getPrototypeOf(buffer.toJSON()))//{}可见toJSON返回对象console.log(buffer[0])//97console.log(buffer.toJSON().data[0])//97console.log(buffer.toJSON().data)//[97,98,99,100,97,98,99,100,97,98]console.log(JSON.stringify(buffer.toJSON()))//转成json字符串buffer遍历buffer.keys(),buffer.values(),buffer.entries()letbuffer=Buffer.alloc(10).fill('abcd');for(letkeyofbuffer.keys()){process.stdout.write(`${key}`)//输出不换行,write只能接受String和Buffer为参数,可以转换通过模板字符串//console.log(key)以便输出换行}//0123456789console.log()for(letvalueofbuffer.values()){process.stdout.write(`${value}`);//9798991009798991009798}console.log('')for(letentryofbuffer.entries()){console.log('buffer[%d]==%d',entry[0],entriy[1])}/*buffer[0]==97buffer[1]==98buffer[2]==99buffer[3]==100buffer[4]==97buffer[5]==98buffer[6]==99buffer[7]==100buffer[8]==97buffer[9]==98*/TODOTypeArrayvsBuffervsArrayBuffer上次第一次在SG上用markdown写文章,体验不是很好,字体肯定小,伤眼睛,代码显示不是很友好,比如,没有行号会有滚动条还有很多其他SG大佬,欢迎指教。参考文章:NodeJS流1:BufferNodejs进阶:核心模块Buffer常用API使用总结想深入了解Node.js中的Buffer吗?看一下这个。