Node.js中你不可不精的Stream(流)

一、什么是Stream(流)

流(stream)在 Node.js 中是处理流数据的抽象接口(abstract interface)。 stream 模块提供了基础的API。使用这些API可以很容易地来构建实现流接口的对象。例如, HTTP 请求 和 process.stdout 就都是流的实例。
流可以是可读的、可写的,或是可读写的。注意,所有的流都是 EventEmitter 的实例。

二、流的类型

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

  • Readable - 可读的流 (例如 fs.createReadStream())。
  • Writable - 可写的流 (例如 fs.createWriteStream())。
  • Duplex - 可读写的流(双工流) (例如 net.Socket)。
  • Transform - 在读写过程中可以修改和变换数据的 Duplex 流 (例如 zlib.createDeflate())。
var Stream = require('stream') //stream 模块引入方式

var Readable = Stream.Readable //可读的流
var Writable = Stream.Writable //可写的流
var Duplex = Stream.Duplex //可读写的流
var Transform = Stream.Transform //在读写过程中可以修改和变换数据的 Duplex 流

Node.js中关于流的操作被封装到了Stream模块中,这个模块也被多个核心模块所引用。例如在fs.createReadStream()和fs.createWriteStream()的源码实现里,都调用了Stream模块提供的抽象接口来实现对流数据的操作。

三、为什么使用Stream?

我们通过两个例子,了解一下为什么要使用Stream。

Exp1:

下面是一个读取文件内容的例子:

const fs = require('fs')

fs.readFile(file, function (err, content) { //读出来的content是Buffer
 console.log(content)
 console.log(content.toString())
})

但如果文件内容较大,譬如在500M时,执行上述代码的输出为:

<Buffer 64 74 09 75 61 09 63 6f 75 6e 74 0a 0a 64 74 09 75 61 09 63 6f 75 6e 74 0a 32 30 31 35 31 32 30 38 09 4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 63 6f 6d ... >
buffer.js:382
 throw new Error('toString failed');
 ^

Error: toString failed
 at Buffer.toString (buffer.js:382:11)

报错的原因是content这个Buffer对象的长度过大,导致toString方法失败。

可见,这种一次获取全部内容的做法,不适合操作大文件。

可以考虑使用流来读取文件内容。

var fs = require('fs')
fs.createReadStream(bigFile).pipe(process.stdout) 

fs.createReadStream创建一个可读流,连接了源头(上游,文件)和消耗方(下游,标准输出)。

执行上面代码时,流会逐次调用fs.read(ReadStream这个类的源码里有一个_read方法,这个_read方法在内部调用了fs.read来实现对文件的读取),将文件中的内容分批取出传给下游。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/68.html