在文件看来,它的内容被分块地连续取走了。
在下游看来,它收到的是一个先后到达的数据序列。
如果不需要一次操作全部内容,它可以处理完一个数据便丢掉。
在流看来,任一时刻它都只存储了文件中的一部分数据,只是内容在变化而已。
这种情况就像是用水管去取池子中的水。
每当用掉一点水,水管便会从池子中再取出一点。
无论水池有多大,都只存储了与水管容积等量的水。
Exp2:
下面是一个在线看视频的例子,假定我们通过HTTP请求返回视频内容给用户
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { fs.readFile(videoPath, (err, data) => { res.end(data); }); }).listen(8080);
但这样有两个明显的问题
- 视频文件需要全部读取完,才能返回给用户,这样等待时间会很长。
- 视频文件一次全放入内存中,内存吃不消。
用流可以将视频文件一点一点读到内存中,再一点一点返回给用户,读一部分,写一部分。(利用了 HTTP 协议的 Transfer-Encoding: chunked 分段传输特性),用户体验得到优化,同时对内存的开销明显下降。
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { fs.createReadStream(videoPath).pipe(res); }).listen(8080);
通过上述两个例子,我们知道,在大数据情况下必须使用流式处理。
四、可读流(Readable Stream)
可读流(Readable streams)是对提供数据的源头(source)的抽象。
常见的可读流:
- HTTP responses, on the client
- HTTP requests, on the server
- fs read streams
- TCP sockets //sockets是一个双工流,即可读可写的流
- process.stdin //标准输入
所有的 Readable Stream 都实现了 stream.Readable 类定义的接口。
可读流的两种模式(flowing 和 paused)
- 在 flowing 模式下,可读流自动从系统底层读取数据,并通过 EventEmitter 接口的事件尽快将数据提供给应用(所有的流都是 EventEmitter 的实例)。
- 在 paused 模式下,必须显式调用 stream.read()方法来从流中读取数据片段。
创建流的Readable流,默认是非流动模式(paused模式),默认不会读取数据。所有初始工作模式为paused的Readable流,可以通过下面三种途径切换为flowing模式:
- 监听'data'事件
- 调用stream.resume()方法
- 调用stream.pipe()方法将数据发送到Writable