我爱编程

Node.js Buffer(一、初学者的角度了解Buffer)

2017-04-17  本文已影响0人  小菜荔枝

Buffer

稳定性:2-Stable

0x01 为什么要用Buffer

众所周知,JavaScript与C/C++不同,没有读写二进制流的机制也无法操作内存。在ECMAScript 2015(ES6)中,TypedArray可以有效的解决这个问题,它允许开发者以数组下标的形式操作内存,大大增强了JavaScript处理二进制数据的能力。其实Buffer的功能与TypedArray相同,它为node.js提供了处理内存的功能,如操作TCP流,文件系统等。相比之下,Buffer的一些功能在V8引擎的助力下性能可以发挥得更好。因此推荐在node.js的开发中使用Buffer(当然,使用ES6的TypedArray也可以)

以下是官网的一些简单事例:

// Creates a zero-filled Buffer of length 10.
const buf1 = Buffer.alloc(10);

// Creates a Buffer of length 10, filled with 0x1.
const buf2 = Buffer.alloc(10, 1);

// Creates an uninitialized buffer of length 10.
// This is faster than calling Buffer.alloc() but the returned
// Buffer instance might contain old data that needs to be
// overwritten using either fill() or write().
const buf3 = Buffer.allocUnsafe(10);

// Creates a Buffer containing [0x1, 0x2, 0x3].
const buf4 = Buffer.from([1, 2, 3]);

// Creates a Buffer containing ASCII bytes [0x74, 0x65, 0x73, 0x74].
const buf5 = Buffer.from('test');

// Creates a Buffer containing UTF-8 bytes [0x74, 0xc3, 0xa9, 0x73, 0x74].
const buf6 = Buffer.from('tést', 'utf8');

不吹不黑,作者亲身经历,掌握好以下两种技能可以帮助你更快的理解这篇文章和官方文档:

0x02 Buffer.from(), Buffer.alloc(), and Buffer.allocUnsafe()

Node.js V6版本之前,Buffer实例是通过Buffer构造函数创建的,构造函数的传参不同,创建的实例也是不同的

以上可知,new Buffer()根据第一个参数的类型不同,分配的内存有很大的差别,且程序也不会对new Buffer()的参数进行正确性校验,或是当初始化Buffer内存数据失败时,这些都会不经意地给您的代码带来安全性和可靠性问题。为了使创建Buffer实例的过程更加安全和可靠,各种形式的new Buffer()都是反对使用的,开发人员可能要改造有关new Buffer()的代码,用Buffer.from()Buffer.alloc()Buffer.allocUnsafe()等方法来代替。

通过Buffer.allocUnsafe()创建的Buffer实例可能会分配共享内存池的内存,如果它的大小小于等于Buffer.poolSize的一半。通过Buffer.allocUnsafeSlow()创建的内存则永远不会使用共享内存池。

0x03 命令行参数:--zero-fill-buffers

--zero-fill-buffer参数的作用是:new Buffer(size)Buffer.allocUnsafe()Buffer.allocUnsafeSlow()或者new SlowBuffer(size)创建的实例的内存都会被0填满。使用这个参数将改变这些方法的执行结果和性能,只有在需要强制创建没有敏感数据的Buffer实例时推荐使用

$ node --zeor-file-buffers
> Buffer.allocUnsafe(5); 
// <Buffer 00 00 00 00 00>
// 如果不加这个参数则Buffer的数据可能是别的

0x04 为什么 Buffer.allocUnsafe() 和 Buffer.allocUnsafeSlow() 不安全

当调用Buffer.allocUnsafe()Buffer.allocUnsafeSlow()时,分配的内存段没有初始化(内存没有清零),这个设计使得分配内存的过程非常快,但分配的内存可能潜在地包含敏感数据。所以调用Buffer.allocUnsafe()创建的Buffer实例如果没有对分配的内存段的数据进行重写,当对这个Buffer进行读操作时,敏感的数据就会泄露。当考虑性能方面的优势使用Buffer.allocUnsafe()时,一定要避免这个安全漏洞。

0x05 Buffers and ES6 iteration

Buffer实例可以使用ECMAScript 2015 (ES6) for...of语法

const buf = Buffer.from([1, 2, 3]);

// Prints:
//   1
//   2
//   3
for (const b of buf) {
  console.log(b);
}

另外说明的是,buf.values()buf.keys()buf.entries() 也可以创建iterators (遍历器)

0x06 Buffers and Character Encodings

Buffer实例通常用来表述字符编码的序列,例如UTF-8,UCS2,Base64,甚至十六进制的数据。通过指定的字符编码,Buffer和JavaScript字符串可以相互转换。

const buf = Buffer.from('hello world', 'ascii');

// Prints: 68656c6c6f20776f726c64
console.log(buf.toString('hex'));

// Prints: aGVsbG8gd29ybGQ=
console.log(buf.toString('base64'));

目前Node.js支持的字符编码有:

注意:当今浏览器遵循的是WHATWG spec标准,'latin1''ISO-8859-1'都属于'win-1252'编码的一种('win-1252'还包含其他的编码)。这意味着如果有些操作如http.get(),它返回的字符是WHATWG spec的'win-1252'编码的数据,使用'latin1'进行解码得到的数据可能是不正确的。

0x07 Buffers and TypedArray

Buffer实例也是Unit8Array视图。但是它与ECMAScript 2015的TypedArray还有些细微的不同。例如,ArrayBuffer#slice()创建实例的内存是slice方法拷贝的内存,而Buffer#slice()是在Buffer的基础上创建了视图来操作内存,所以Buffer#slice()的效率更高一些
通过Buffer创建二进制数组时要注意下面几点:

通过TypedArray对象的.buffer属性创建的Buffer实例与TypedArray实例共享同一个内存

const arr = new Uint16Array(2);// arr是TypedArray

arr[0] = 5000;
arr[1] = 4000;

// 拷贝`arr`的内存
const buf1 = Buffer.from(arr);

// 共享`arr`的内存
const buf2 = Buffer.from(arr.buffer);

// Prints: <Buffer 88 a0>
console.log(buf1);

// Prints: <Buffer 88 13 a0 0f>
console.log(buf2);

arr[1] = 6000;

// Prints: <Buffer 88 a0>
console.log(buf1);

// Prints: <Buffer 88 13 70 17>
console.log(buf2);

通过TypedArray.buffer创建Buffer时,可以通过byteOffsetlength参数使用ArrayTyped的部分内存

const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);

// Prints: 16
console.log(buf.length);

Buffer.from()TypedArray.from()方法是不同的,TypedArray.from()的第二个参数是一个mapping遍历的函数:

Buffer.from()并不支持这个mapping函数:

总结:这篇文章首先回答了为什么要使用Buffer,然后详述了Buffer的功能、效率、安全性及一些使用上的问题,使读者对其概念有一个初步的了解,下一章将会带大家深入了解Class Buffer的具体使用方法,敬请期待。

本文档是根据Node.js目前稳定版本的文档Node.js v6.10.2 Documentation进行总结的,如您在阅读的过程中发现问题,请联系作者,最后感谢您的支持!

简书作者 小菜荔枝 转载请联系作者获得授权

上一篇 下一篇

猜你喜欢

热点阅读