乐趣区

学Node必须掌握的Buffer和Stream

本文并不介绍 Buffer 和 Stream 使用的 api,而是把对 Buffer 和 Stream 的理解带给大家。

之前发了篇文章《Nodejs 核心模块简介》,笼统的介绍了下 Events 模块、fs 模块、stream 的使用、http 模块。

文章也在我的 github 博客上,欢迎订阅。

因为想学好 node 这些东西几乎是必须掌握的。这篇文章来说一下在 node 中几乎无处不在的 Buffer 和 Stream,什么是 Buffer 以及它和 Stream 到底什么关系?马上揭晓。

Buffer

Buffer 是个类数组的对象,可以把它当做数组更好理解些,只不过里面存的是二进制数据。

先创建个 buffer 来看看它打印出来的样子:

const str = 'hello';
const buf = Buffer.from(str);

console.log(buf); // <Buffer 68 65 6c 6c 6f>

buf 里装的数据是字符串 hello,而 buf 的长度为 5,hello 的长度也是 5,所以 Buffer 中每个元素占一个字节(英文每个字母是一个字节)。

Buffer 是什么

从代码使用来看,Buffer 是类数组对象。
从内存角度看,Buffer 是在内存中开辟的一块区域。

Buffer 翻译过来是 缓冲器, 它主要用来暂存数据。

为了更好理解,用大白话把上面哪句翻译一下:Buffer 就是我们常坐的 公交车 就是数据,人上车就表示在 Buffer 中输入数据,到站了人就下车,Buffer 里的数据就会输出

比如我们填写完表单,发送 http 请求到服务端,我们的数据就会暂存在 Buffer 中,服务端取的数据就是从暂存的 Buffer 里取的

Buffer 里装的是什么

废话!装的当然是数据了!没错 是数据 …

<Buffer 68 65 6c 6c 6f>, 从刚才打印结果看,Buffer 显示的每个元素都是 十六进制,但这只是为了方面查看,在控制台显示时是十六进制而已。。。

这里问问大家,数据在内存中是什么?没错 是二进制,就是类似 010101 这样的东西。
为什么以二进制存在?因为电脑读写的数据都是 电信号 !而电信号就是 01

好在我们可以把二进制、十进制、十六进制等进行转换,所以 Buffer 的每个元素看上去是十六进制,其实内存里存的都是二进制。

Buffer 的每个元素取值范围是多少呢?

  • 00 – ff(十六进制)
  • 0 – 255(十进制)
  • 00000000 – 11111111(二进制)

255 这个数字肯定见过不少,比如 css 中的 rgba 每个值的范围是 0-255

而 255 其实跟 ASCII 码 紧紧相连,回顾一下上面代码中打印 hello 的 buffer:<Buffer 68 65 6c 6c 6f>,然后对照下面这个 ASCII 表

再对照 buffer 里的每个元素:

是不是一下就明白了,原来数据就是这样纸的呀。
当然,上面的 hello 使用的是国际统一码,是 0 - 127,后 128 个 (128—255) 称为扩展 ASCII 码,目前许多基于 x86 的系统都支持使用扩展(或“高”)ASCII。

Stream 与 Buffer

亲!先把进制问题和 ASCII 码放一边,现在你的脑子里只有 公交车

Stream 翻译过来就是流,流动的意思,《Nodejs 核心模块简介》里也简单的介绍了这块内容,有兴趣可以看看。

既然 Stream 是流动的,那它跟 Buffer 到底有啥联系?

现在回到 人和公交车 的问题,上面说 是数据,公交车 本身是 Buffer,Buffer 里有没有数据 取决于 在不在里面。

注意,我上面说的是 公交车本身,没有说公交车有没有在跑。

所以,聪明的你猜到了,跑着的公交车就是 Stream。

流的原则是:有源头、有终点、源头流向终点。
公交车就是这样,从起点发车,载着数据 (人) 往终点跑。

光说不行,来看一段代码:

const fileReadStream = fs.createReadStream('./logs/hello.log');
const fileWriteStream = fs.createWriteStream('./logs/hello2.log');

fileReadStream.on('data', chunk => {console.log(chunk);
  fileWriteStream.write(chunk); 
});

打印结果如下:

从图看出,hello.log数据很多,一个 buffer(公交车)装不完,打印了好几次的 chunk 才完成写入,每个 chunk 都是一个 buffer,都填满了数据 (人)。流可以看成是公交司机,流的作用就是将 buffer 从一个地方(起点) 运送的另一个地方(终点)。

总结

现在捋一下:

  1. Buffer 就是在内存中开辟一段空间,用来装数据的
  2. 数据都是二进制的,记住电信号(010101)
  3. Stream 的三大原则:有源头、有终点、源头流向终点。
  4. Stream 就像司机,它的作用就是将装着数据的 Buffer 开向终点
退出移动版