七、stream

197 阅读3分钟

认识Stream

  • 什么是流呢?

    • 我们的第一反应应该是流水,源源不断的流动;

    • 程序中的流也是类似的含义,我们可以想象当我们从一个文件中读取数据时,文件的二进制(字节)数据会源源不 断的被读取到我们程序中;

    • 而这个一连串的字节,就是我们程序中的流;

  • 所以,我们可以这样理解流:

    • 是连续字节的一种表现形式和抽象概念;

    • 流应该是可读的,也是可写的;

  • 在之前学习文件的读写时,我们可以直接通过 readFile或者 writeFile方式读写文件,为什么还需要流呢?

    • 直接读写文件的方式,虽然简单,但是无法控制一些细节的操作;

    • 比如从什么位置开始读、读到什么位置、一次性读取多少个字节;

    • 读到某个位置后,暂停读取,某个时刻恢复读取等等;

    • 或者这个文件非常大,比如一个视频文件,一次性全部读取并不合适;

文件读写的Stream

  • 事实上Node中很多对象是基于流实现的:

    • http模块的Request和Response对象;

    • process.stdout对象;

  • 官方:另外所有的流都是EventEmitter的实例:

  • Node.js中有四种基本流类型:

    • Writable:可以向其写入数据的流(例如 fs.createWriteStream())。

    • Readable:可以从中读取数据的流(例如 fs.createReadStream())。

    • Duplex:同时为Readable和的流Writable(例如 net.Socket)。

    • Transform:Duplex可以在写入和读取数据时修改或转换数据的流(例如zlib.createDeflate())。

Readable

  • 之前我们读取一个文件的信息:

    image.png

  • 这种方式是一次性将一个文件中所有的内容都读取到程序(内存)中,但是这种读取方式就会出现我们之前提到的 很多问题:

    • 文件过大、读取的位置、结束的位置、一次读取的大小;
  • 这个时候,我们可以使用 createReadStream,我们来看几个参数,更多参数可以参考官网:

    • start:文件读取开始的位置;

    • end:文件读取结束的位置;

    • highWaterMark:一次性读取字节的长度,默认是64kb;

Readable的使用

  • 创建文件的Readable

    image.png

  • 我们如何获取到数据呢?

    image.png

  • 也可以做一些其他的操作:监听其他事件、暂停或者恢复

    image.png

Writable

  • 之前我们写入一个文件的方式是这样的:

    image.png

  • 这种方式相当于一次性将所有的内容写入到文件中,但是这种方式也有很多问题:

    • 比如我们希望一点点写入内容,精确每次写入的位置等;
  • 这个时候,我们可以使用 createWriteStream,我们来看几个参数,更多参数可以参考官网:

    • flags:默认是w,如果我们希望是追加写入,可以使用 a或者 a+;

    • start:写入的位置;

Writable的使用

  • 我们进行一次简单的写入

    image.png

  • 你可以监听open事件:

    image.png

close的监听

  • 我们会发现,我们并不能监听到 close 事件:

    • 这是因为写入流在打开后是不会自动关闭的;

    • 我们必须手动关闭,来告诉Node已经写入结束了;

    • 并且会发出一个 finish 事件的;

  • 另外一个非常常用的方法是 end:end方法相当于做了两步操作: write传入的数据和调用close方法;

    image.png

pipe方法

  • 正常情况下,我们可以将读取到的 输入流,手动的放到 输出流中进行写入:

    image.png

  • 我们也可以通过pipe来完成这样的操作:

    image.png