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

NodeJS文档中Buffer(1)-Buffer简介

时间:2023-04-03 15:04:48 Node.js

Buffer在ECMAScript2015(ES6)中引入TypedArray之前,JavaScript中并没有读取或操作二进制数据流的机制。Buffer类作为Node.js标准API的一部分引入,支持在TCP流和文件系统操作等上下文中通过8位字节流进行交互。现在TypedArray已经添加到ES6中,Buffer类以更优化和Node.js友好的方式实现了Uint8ArrayAPI。Buffer类的实例类似于一个整型数组,但它被分配到V8堆外的固定大小原始内存(堆外内存,不受V8引擎控制)。缓冲区的大小是在创建时确定的,不能调整大小。Buffer类在Node.js中是一个全局变量,所以不需要使用require('buffer').Buffer。//创建一个长度为10的“0填充”Buffer实例constbuf1=Buffer.alloc(10);//创建一个长度为10的Buffer并用0x1填充它constbuf2=Buffer.alloc(10,0x1);//创建一个长度为10的未初始化缓冲区//这种方法比使用Buffer.alloc()更快,但返回的Buffer实例可能包含之前的旧数据。//需要使用fill()或write()重写。constbuf3=Buffer.allocUnsafe(10);//创建一个包含[0x1,0x2,0x3]的缓冲区constbuf4=Buffer.from([1,2,3]);//创建一个包含UTF-8字的缓冲区Buffer[0x74,0xc3,0xa9,0x73,0x74]constbuf5=Buffer.from('tést');//创建一个包含Latin-1字节的缓冲区[0x74,0xe9,0x73,0x74]constbuf6=Buffer.from('tést','latin-1');Buffer.from()、Buffer.alloc()、Buffer.allocUnsafe()是在v6Buffer实例之前的Node.js版本中使用Buffer构造函数创建的,该函数根据提供的参数以不同方式分配返回的Buffer:传递作为Buffer()的第一个参数的数字(例如newBuffer(10))分配指定大小的新Buffer对象。为这些缓冲区实例分配的内存未初始化,可能包含敏感数据。这样的缓冲区实例必须通过使用buf.fill(0)或完全写入缓冲区来手动初始化。虽然此行为旨在提高性能,但开发经验表明,需要更清楚地区分创建快速但未初始化的缓冲区和创建速度较慢但更安全的缓冲区。传递一个字符串、数组或缓冲区作为第一个参数,将传递的对象的数据复制到缓冲区中。传递ArrayBuffer返回一个Buffer,它与给定的ArrayBuffer共享分配的内存。因为newBuffer()的行为是根据第一个参数传入的值的类型来选择具体的操作,如果没有给newBuffer()传入正确的参数或者新分配的Buffer中的缓冲区内容不正确初始化。然后,此类应用程序会无意中将与安全性和可靠性相关的问题引入其代码中。为了使缓冲区实例的创建更可靠且更不容易出错,这种形式的newBuffer()构造函数已被弃用,请使用Buffer.from()、Buffer.alloc()或Buffer.allocUnsafe()方法取代。开发人员应将他们当前对新Buffer()函数的使用迁移到以下这些新API之一。Buffer.from(array)返回一个新缓冲区,其中包含提供的八位字节的副本。Buffer.from(arrayBuffer[,byteOffset[,length]])返回一个新缓冲区,它与给定的ArrayBuffer共享相同的分配内存。Buffer.from(buffer)返回一个新缓冲区,其中包含给定缓冲区内容的副本。Buffer.from(string[,encoding])返回一个包含所提供字符串副本的新缓冲区。Buffer.alloc(size[,fill[,encoding]])返回指定大小的“已填充”Buffer实例。此方法虽然比Buffer.allocUnsafe(size)方法慢得多,但可确保新创建的Buffer实例不包含陈旧和潜在敏感数据。Buffer.allocUnsafe(size)和Buffer.allocUnsafeSlow(size)都返回指定大小的新缓冲区,其内容必须用buf.fill(0)初始化或完全写入新内容以覆盖旧的敏感数据。Buffer.allocUnsafe()返回的buffer实例大小小于等于Buffer.poolSize的一半,所以可以在内部共享内存池中分配。Buffer.allocUnsafeSlow()返回的实例不会使用内部共享内存池。--zero-fill-buffers命令行参数Node.js可以通过--zero-fill-buffers命令行参数启动,强制所有新分配的Buffer实例使用newBuffer(size),Buffer.allocUnsafe(),Buffer.allocUnsafeSlow()或newSlowBuffer()在创建时自动为0。使用此参数会更改这些方法的默认行为,并对性能产生重大影响。建议仅在必要时强制执行--zero-fill-buffers选项,以确保新分配的缓冲区实例不包含潜在的敏感数据。$node--zero-fill-buffers>Buffer.allocUnsafe(5);为什么Buffer.allocUnsafe()和Buffer.allocUnsafeSlow()不安全?当调用Buffer.allocUnsafe()和Buffer.allocUnsafeSlow()时,分配的内存段未初始化(未归零)。虽然这种设计使内存分配相当快,但分配的内存段可能包含潜在的敏感旧数据。使用由Buffer.allocUnsafe()创建的缓冲区而不完全重新覆盖内存可能会在读取缓冲区内存时泄漏此类旧数据。虽然使用Buffer.allocUnsafe()有明显的性能优势,但必须格外小心以避免在应用程序中引入安全漏洞。缓冲区和字符编码缓冲区实例通常用于表示编码字符序列,例如UTF-8、UCS2、Base64甚至十六进制编码数据。通过使用字符编码声明字符串,可以在缓冲区实例和普通JavaScript字符串之间来回转换。constbuf=Buffer.from('helloworld','ascii');console.log(buf.toString('hex'));//=>68656c6c6f20776f726c64console.log(buf.toString('base64'));//=>aGVsbG8gd29ybGQ=Node.js当前支持的字符编码包括:asciiutf8utf16leucs2base64latin1binaryhex注意:今天的浏览器遵循WHATWG规范,将“latin1”和ISO-8859-1合并到win-1252中。这意味着在做类似http.get()的操作时,如果返回的字符集在WHATWG规范中列出的范围内,服务器实际上可能返回win-1252编码的数据,此时使用“latin1”编码可以错误地解码字符,导致乱码。Buffers和TypeArrayBuffer实例也是Uint8Array实例。但是,与ECMAScript2015中的TypedArray规范存在轻微的不兼容。例如,虽然ArrayBuffer#slice()创建切片的副本,但Buffer#slice()实现创建现有Buffer的副本而不创建副本,从而使Buffer#slice()更高效。在Buffer中新建TypedArray实例时,需要注意以下几点:Buffer对象的内存是从TypedArray复制过来的,不是共享的。Buffer对象的内存可以解释为不同元素的数组,而不是目标类型的字节数组。也就是说newUint32Array(Buffer.from([1,2,3,4]))通过数组[1,2,3,4]创建一个长度为4的Uint32Array,而不是通过[0x1020304]或者[0x4030201]创建一个长度为1的Uint32Array。可以使用TypeArray对象的.buffer属性创建一个新的Buffer,它与TypedArray实例共享相同的分配内存。constarr=newUint16Array(2);arr[0]=5000;arr[1]=4000;constbuf1=Buffer.from(arr);constbuf2=Buffer.from(arr.buffer);console.log(buf1);//=><缓冲区88a0>console.log(buf2);//=><缓冲区8813a00f>arr[1]=6000;console.log(buf1);//=><缓冲区88a0>console.log(buf2);//=>注意在使用TypedArray的.buffer创建Buffer时,可以通过传入byteOffset和length参数来使用ArrayBuffer的一部分。constarr=newUint16Array(20);constbuf=newBuffer.from(arr.buffer,0,16);控制台日志(buf.length);//=>16Buffer.from()和TypedArray.from()有不同的函数签名和实现。具体来说,TypedArray变量接受第二个参数,它是要在类型化数组的每个元素上调用的映射函数:TypedArray.from(source[,mapFn[,thisArg]])Float32Array.from([1,2,3],x=>x+x);//Float32Array[2,4,6]但是Buffer.from()方法不支持使用映射函数:Buffer.from(array)Buffer.from(buffer)Buffer.from(arrayBuffer[,byteOffset[,length]])Buffer.from(string[,encoding])缓冲区和ES6迭代器可以使用ECMAScript2015(ES6)for..of语法来迭代缓冲区实例。constbuf=Buffer.from([1,2,3]);for(constbofbuf){console.log(b));//=>123}另外,buf.values(),buf.keys()和buf.entries()方法都可以用来创建迭代器。