Node.js Stream(流)
Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。 下面我们通过可读流(fs.createReadStream),来了解一下流到底是怎么回事。
先看一下流的类型和常用的事件:
Node.js,Stream 有四种流类型:
- Readable - 可读操作。
- Writable - 可写操作。
- Duplex - 可读可写操作.
- Transform - 操作被写入数据,然后读出结果。
所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:
- data - 当有数据可读时触发。
- end - 没有更多的数据可读时触发。
- error - 在接收和写入过程中发生错误时触发。
- close - 关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)。不直接调 用此方法,而应确保流得以正确释放。
看完上述是否觉得很枯燥,没关系下面让小白给大家讲个故事,看看可读流的使用到底怎么回事:
小白:皮皮虾每天上班必经过京承收费站,今天也不例外严重堵车了,更加倒霉的是:
收费站管理员:今天由于发生了一起很大交通事故,每通过一量车,收费站需要暂时关闭,5分钟之后再开启,下一辆车再过去。(highWaterMark:1,每次过一辆车)
皮皮虾:oh my god!上帝啊,我要迟到了,这是件很严重的事情(因为我这个月已经迟到6次了,额,多么吉利的数字啊,好吧,我闭嘴......)
小白:这时候,等啊等,等啊等,终于前边还有两辆车,就轮到皮皮虾了,收费站管理员开启了开关,一辆车过去了开关关闭了,等了5分钟之后,管理员打开了开关,第二辆车过去了,开关关闭了。
rs.on('data',function (data) {
console.log(data);
rs.pause();
});
setTimeout(()=>{rs.resume()},50000)
复制代码
收费站管理员:恩,等五分钟再把开关,打开,我先玩会吃鸡的游戏。
小白:这下好了,游戏玩起来,一发不可收拾,居然忘记了打开开关,最终悲剧发生了,皮皮虾一天没上班,一天都在路上了,(也导致了end事件和close事件没有执行)当然,玩游戏的收费站大叔也由于被投诉,而遭到公司的开除。
好了故事讲完了,接下来看一下完整的代码,是不是更容易理解了呢?
可读流的小例子:
let fs = require('fs');
let rs = fs.createReadStream('./context.txt', {
highWaterMark: 1,
flags:'r',
autoClose:true,
start:0,
end:3,
encoding:'utf8'
});
rs.on('error',function (err) {
console.log(err)
});
rs.on('open',function () {
console.log('文件打开了');
});
rs.on('data',function (data) {
console.log(data);
rs.pause();
});
setTimeout(()=>{rs.resume()},50000)
rs.on('end',function () {
console.log('读取完毕了');
});
rs.on('close',function () {
console.log('关闭')
});
复制代码
以上代码的运行结果为:
文件打开了
1
2
复制代码
总结:
1, context.txt文件的内容:123456789;
2, highWaterMark: 1, 读取1个字节,默认64k;
3, encoding:'utf8', encoding 读取默认都是buffer;
4, autoClose:true, 默认读取完毕后自动关闭;
5, 流是闭合区间 包start也包end;
6, rs.pause(); 暂停触发on('data')事件,将流动模式又转化成了非流动模式;
7, on data事件是循环执行的,直到文件读完;
复制代码