宝哥软件园

谈Node.js:缓冲模块

编辑:宝哥软件园 来源:互联网 时间:2021-09-07

Javascript对客户端的unicode编码数据操作非常友好,但二进制数据的处理却不尽如人意。为了处理二进制数据或非unicode编码的数据,Node.js设计了Buffer类,实现了Uint8Array接口并对其进行了优化。它的实例类似于整数数组,但其大小在创建后无法调整。在介绍如何使用Buffer之前,首先要介绍一些知识点。

1.V8发动机内存使用限制

默认情况下,32位系统上V8引擎的最大堆内存使用量为512M,64位系统上为1GB。虽然可以使用-max-old-space-size参数来调整该值,但在使用大内存时,建议使用Buffer或Stream,因为Buffer的内存分配不在V8堆上。

2.单个缓冲区实例的大小限制

单个Buffer实例的最大大小值为1GB-1(32位系统)或2GB-1(64位系统),因此在创建Buffer实例时不能超过该值,或者使用readFile()方法读取大文件,否则将引发RangeError错误。

3.8KB池

创建Buffer实例时,当用户请求的空间大于8KB时,Nodejs会直接调用内部的createUnsafeBuffer()方法来创建Buffer。如果请求的空间大于0且小于4KB,新的缓冲区将建立在当前的8kb SLAB上,剩余的空间将被更新,如下图所示:

以下描述了缓冲区应用编程接口的简单使用:

1.创建缓冲实例

使用缓冲区。from(),缓冲区。alloc(),缓冲区。allocsafe()和其他方法来创建缓冲区实例。6.0版之前由构造函数直接创建的方法new Buffer()已被丢弃,不建议使用,因为它可能会导致内存泄漏。方法buffer.alloc(大小[,填充[,编码]]具有以下参数含义:

Size,指定缓冲区的长度,但不能超过buffer.kMaxLength如果不是数字,则报告填充错误。指定初始化缓冲区的值,默认值为0编码。如果fill是字符串,则参数指定fill的编码如下:

const buf 1=Buffer . alloc(10);console . log(buf 1);//Buffer 00 00 00 00 00 00 00 00 00 00 00 00 const buf 2=Buffer . alloc(10,' hello ');console . log(buf 2);//Buffer 68 65 6c 6f 68 65 6c 6f con ST buff 3=Buffer . alloc(10,' hello ',' base64 ');console . log(buf 3);//buffer 85 e 965 85 e 965 85 e 965 85 method buffer . allocunsafe(size),size参数指定了缓冲区的大小,这个方法返回一个未初始化的缓冲区,所以它仍然可能保留敏感数据,造成信息泄露。建议用buffer.fill(0)初始化缓冲区,与buffer.alloc(大小,使用如下:

const buf 4=buffer . allocunsafe(10);console . log(buf 4);//buffer 68 fb4d 00 00 00 00 00 00 00 00 00 08 00,可以看作buff 4 . fill(0)有数据;console . log(buf 4);//Buffer 00 00 00 00 00 00 00 00 00 00 00 00方法Buffer.allocUnsafeSlow(大小),参数含义同上,此方法不使用缓冲池,容易造成内存浪费,其用法如下:

const buf 5=buffer . allocansafeslow(10);console . log(buf 5);//缓冲区38 00 24 00 00 00 00 00 00 00 00 00 00 00方法缓冲区. from(值,[.]),这里有四种情况,如下所示:

首先,该值是一个十六进制数组,该数组被转换为缓冲区。如果不是十六进制,它将被转换如下:

const buf6=Buffer.from([1,2,3,5,17]);console . log(buf 6);//Buffer 01 02 03 05 11其次,如果value是一个字符串,那么这个字符串会被转换为Buffer,并且这个方法会使用缓冲池,如下所示:

const buf 7=buffer . from(' hello world!');console . log(buf 7);//buffer 01 02 03 05 11第三,如果value是buffer的一个实例,则将该值复制到新的Buffer中,在新的Buffer中它只是该值的一个副本,不会共享内存,如下所示:

const buf 8=缓冲区。from(' hello world ');const buf 9=buff。from(buf 8);控制台。log(buf 8);//缓冲区68 65 6c 6f 20 77 6f 72 6c 64控制台。log(buf 9);//缓冲区68 65 6c 6f 20 77 6f 72 6c 64 buf 9[0]=0x 66;控制台。log(buf 8);//缓冲区68 65 6c 6f 20 77 6f 72 6c 64控制台。log(buf 9);//缓冲区6c 6c 6f 20 77 6f 72 6c 64第四,值为arrayBuffer时,还有两个可选参数[,字节集合[,长度]],字节集合指定从arrayBuffer开始复制的位置,长度复制的长度。如下:

const arr=新的Uint 8数组(2);arr[0]=128;arr[1]=200;const buf10=Buffer.from(arr,0,2);控制台。log(buf 10);//缓冲区80 c8如果引用的是缓冲区,则新创建的缓冲buf10与到达)共享内存,如下:

const arr=新的Uint 8数组(2);arr[0]=128;arr[1]=200;const buf 10=缓冲区。来自(arr。缓冲);arr[0]=254;控制台。log(buf 10);//缓冲fe c82、缓冲解码

使用buf。tostring([编码[,开始[,结束]])方法将缓冲器转换成字符串编码指定字符编码,默认为utf8 ',开始开始位置,结束结束位置(不包括),目前编码只支持ascii、utf8、utf16le、ucs2、base64、latin1、二进制、十六进制,使用如下所示:

const buf12=缓冲区。' from('我爱中国');控制台。日志(buf 12。ToString(' base64 ');//5 oir 54 ix5lit 5 zu9控制台。日志(buf 12。tostring(' utf8 ');//我爱中国控制台。日志(buf 12。ToString(' hex ');//e68891e788b1e4b8ade59bbd3、缓冲器拼接、复制、填充、分割

方法buf.fill(值[,偏移量[,结束]][,编码])使用指定的值填充缓冲区,参数抵消指定填充的起始位置,结束为结束位置,使用如下所示:

控制台日志缓冲区允许安全(5)。填充(' a ').toString());//aaaaconsole。日志(缓冲区。allocunsafe(5)).填充(65)。toString(' utf8 ');//AAAAA方法Buffer.concat(list[,TotaL Ength])将多个缓冲器合并在一起,并返回一个新的缓冲器实例,参数总计为指定的缓冲的长度总和,如果不提供该值,函数内部会循环去获取每一个缓冲器的长度,然后进行拼接,因此为了速度,最好指定一个总长度,使用如下:

函数bufferInjoin(buff arr){ var len=0;buffArr.forEach((buff,idx,arr)={ len=buff。长度;});var buffer=缓冲区。concat(缓冲区,len);返回缓冲区;} var buff=bufferInjoin([buffer。' from('呵呵),buffer . alloconsafe(5).填充(' a ')]);console.log(缓冲区);//缓冲区68 65 68 65 61 61 61 61 61控制台。日志(缓冲区。长度);//9控制台。日志(缓冲。tostring());//呵呵呵方法buf.copy(目标[,目标开始[,源开始[,源结束]])可以实现buf到目标的复制,参数含义如下:

目标,复制目标targetStart,复制目标开始被覆盖的位置sourceStart,复制源开始复制的位置sourceEnd,复制源复制结束的位置使用如下所示:

const buf 1=缓冲区。来自(' hello world!');const buf2=Buffer.allocUnsafe(5).填充(' x ');buf1.copy(buf2,0,0,5);控制台。日志(buf 2。ToString());//你好方法buf.slice([start[,end]])可以分割缓冲区,返回一个新的缓冲区,但是仍然是引用原缓冲区,因此改变原缓冲器数据,该新缓冲器也会跟着改变,如果参数开始,结束为负数,则先要加上缓冲器的长度再进行计算,如下所示:

const buf 1=缓冲区。来自('你好世界');常量buf 2=buf 1。切片(0);控制台。log(buf 2);//缓冲区68 65 6c 6f 20 77 6f 72 6c 64 2eb F2[0]=88;控制台。log(buf 1);//缓冲区58 65 6c 6f 20 77 6f 72 6c 64 2 econst buf 3=buf 1。切片(-6,-1);控制台。日志(buf 3。ToString());//world3,缓冲区读写

缓冲器写操作通过写开头的写美国石油学会(美国石油协会)来完成,主要有以下这些:

buf.write(字符串[,偏移量[,长度]][,编码]),向缓冲器写入字符串buf.writeDoubleBE(值,偏移量[,noAssert])写入64位浮点型数字,大端对齐buf.writeDoubleLE(值,偏移量[,noAssert]),写入64位浮点型数字,小端对齐buf.writeFloatBE(值,偏移量[,noAssert]),写入32位浮点型数字,大端对齐buf.writeFloatLE(值,偏移量[,noAssert]),写入32位浮点型数字,小端对齐buf.writeInt8(值,偏移量[,noAssert]),写入有符号8位整型数字buf.writeInt16BE(值,偏移量[,noAssert]),写入有符号16位整型数字,大端对齐buf.writeInt16LE(值,偏移量[,noAssert]),写入有符号16位整型数字,小端对齐buf.writeInt32BE(值,偏移量[,noAssert]),写入有符号32位整型数字,大端对齐buf.writeInt32LE(值,偏移量[,noAssert]),写入有符号32位整型数字,小端对齐buf.writeIntBE(值,偏移量,字节长度[,noAssert]),以下便不再累述buf.writeIntLE(值,偏移量,字节长度[,noAssert]) buf.writeUInt8(值,偏移量[,noAssert]) buf。writeuint16be(value,offset[,noAssert])buf。writeuint16le(值,偏移量[,noAssert])buf。writeuint32be(value,offset[,noAssert])buf。writeuint32 le(value,offset[,noAssert])buf。writeuint32 le(值,偏移量[,noasset]).读操作由阅读开头的美国石油学会(美国石油协会)完成,主要有以下这些:

buf.readDoubleBE(offset[,noAssert])buf。readdouble le(offset[,noAssert])buf。readfloat be(offset[,noAssert])buf。readfloat(offset[,noAssert])buf。readnt8(offset[,noAssert])buf。readnt16 be(offset[,noasset])buf。readnt16 le(偏移量[,noasset])buf。readnt32 be(偏移量[,noasset])使用如下所示,以32无符号整型为例:

const buf=缓冲区。allocunsafe(8);buf.writeUInt32BE(0x12345678,0)控制台。日志(buf);常量数据=buf。readuint 32 be(0);控制台。日志(数据。tostring(16));最后利用缓冲器读应用程序接口完成一个获取巴布亚新几内亚格式图片尺寸的小工具,在开始编码之前,先简单介绍下巴布亚新几内亚文件组成,如下所示:

巴布亚新几内亚文件标志巴布亚新几内亚数据块……巴布亚新几内亚数据块

这里我们只要用到巴布亚新几内亚文件标识和巴布亚新几内亚数据块的第一个块IHDR文件头数据块。文件标识是固定的8个字节,为89 50 4E 47 0D 0A IHDR 1A 0A数据块的长度为13个字节,格式如下:

域的名称字节数说明宽度四字节宽度高度四字节高度位深度一字节图像深度颜色类型一字节颜色类型压缩方法一字节压缩方法过滤方法一字节滤波器方法隔行扫描方法一字节隔行扫描方法开始编码,如下所示:

const fs=require(' fs ');const path=require(' path ');const argvs=进程。argv。切片(2);if(argvs。长度=0){控制台。错误(“”请输入图片:png.js img1 img2.");过程。出口(-1);}argvs.forEach((img,idx,arr)={ var stat=fs。stat sync(img);fs.open(img,' r ',(err,FD)={ if(err)throw err;var buff=缓冲区。alloc(stat。大小);fs.read(fd,buff,0,stat.size,0,(err,bytesRead,buffer)={ if(err)throw err;fs.close(fd,()={ });getmgdimension(buff,(err,dimension)={ if(err)throw err;console.log(`${img}的尺寸为:$ { dimension。宽度} x $ { dimension。height } `);});});});});函数getmgdimension(buff,cb){ if((buff.toString('utf8 ',1,8)=' PNG r n x1a n ')(buff。tostring(' utf8 ',12,16)=' IHDR '){ return CB(null,{ width : buff。readuint32 be(16),高度: buff。readuint32 be(20)},0;}否则{返回cb(新错误('不是巴布亚新几内亚图片'),{}),1;}}执行结果如下:

e : 开发文档 nodejsdemonode png。js 20160824083157.png下载。png20160824083157.png的尺寸为:195x195下载。巴布亚新几内亚的尺寸为:720x600

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

更多资讯
游戏推荐
更多+