浅谈手写node可读流之流动模式

node的可读流基于事件

可读流之流动模式,这种流动模式会有一个"开关",每次当"开关"开启的时候,流动模式起作用,如果将这个"开关"设置成暂停的话,那么,这个可读流将不会去读取文件,直到将这个"开关"重新置为流动。

读取文件流程

读取文件内容的流程,主要为:

打开文件,打开文件成功,将触发open事件,如果打开失败,触发error事件和close事件,将文件关闭。

开始读取文件中的内容,监听data事件,数据处于流动状态,可通过修改开关的状态来暂停读取。

每次读取到的内容放入缓存中,并通过data事件将数据发布出去。

当文件中的内容读取完毕之后,将文件关闭。

这一系列动作都是基于事件来进行操作的,而node中的事件我们都知道是一种发布订阅模式来实现的。

下面我们来看一看,node是如何使用可读流来读取文件中的内容?

node 可读流参数

首先我们通过fs模块来创建一个可读流,可读流接受两个参数:

第一个参数是要读取的文件地址,在这里指明你要读取哪个文件。

第二个参数是可选项,这个参数是一个对象,用来指定可读流的一些具体的参数。

如下几个参数我们来一一说明:

highWaterMark:设置高水位线,这个参数主要用于在读取文件时,可读流会将文件中的内容读取到缓存当中,而这里我们需要创建一个buffer来缓存这些数据,所以这个参数是用来设置buffer的大小,如果不对这个参数进行设置的话,可读流默认的配置64k。

flags:这个参数主要用于设置文件的执行模式,比如说我们具体的操作适用于读取文件还是写入文件等这些操作。如果是写入文件的话那我们,使用的是w。如果是读取文件的话那这个操作符就应该是r。

下面这张表格就说明了不同的符号代表不同含义:

符号 含义
r   读文件,文件不存在报错  
r+   读取并写入,文件不存在报错  
rs   同步读取文件并忽略缓存  
w   写入文件,不存在则创建,存在则清空  
wx   排它写入文件  
w+   读取并写入文件,不存在则创建,存在则清空  
wx+   和w+类似,排他方式打开  
a   追加写入  
ax   与a类似,排他方式写入  
a+   读取并追加写入,不存在则创建  
ax+   作用与a+类似,但是以排他方式打开文件  

autoClose:这个参数主要用于,对文件的关闭的一些控制。如果文件再打开的过程或者其他操作的过程中出现了错误的情况下,需要将文件进行关闭。那这个参数是设置文件是否自动关闭的功能。

encoding:node中用buffer来读取文件操作的东西二进制数据。这些数据展现出来的话我们是一堆乱码,所以需要,要我们对这个数据指定一个具体的编码格式。然后将会对这些数据进行编码转化,这样转化出来的数据就是我们能看懂的数据。

starts:这个参数主要用于指定从什么位置开始读取文件中的内容,默认的话是从零开始。

ends:这个参数主要用于指定定具体要读取文件多长的数据,这里需要说明一下,这个参数是包括本身的位置,也就是所谓的包前和包后。

下面我们来看看可读流具体例子:

let fs = require("fs"); let rs = fs.createReadStream("./a.js", { highWaterMark: 3, encoding: "utf8", autoClose: true, start: 0, end: 9 }); rs.on("open", () => {console.log("open");}); rs.on("close", () => {console.log("close");}); rs.on("data", data => { console.log(data); rs.pause();//暂停读取 此时流动模式为暂停模式 }); setInterval(() => { rs.resume();//重新设置为流动模式,开始读取数据 }, 1000); rs.on("end", () => { console.log("end"); }); rs.on("error", err => { console.log(err); });

手写可读流第一步

上面我们说过,node可读流是基于node的核心模块事件来完成的,所以在实现我们自己的可读流时需要继承events模块,代码如下:

let fs = require('fs'); let EventEmitter = require('events'); class ReadStream extends EventEmitter { }

继承了EventEmitter类,我们就可以使用EventEmitter类中的各个方法,并且同样是采用发布订阅的模式了处理事件。

第二步:处理可读流配置的参数

上面我们提到,node中创建可读流时可以对这个流配置具体的参数,比如

let rs = fs.createReadStream("./a.js", { highWaterMark: 3, encoding: "utf8", autoClose: true, start: 0, end: 9 });

那么对于这些参数,我们自己实现的可读流类也需要对这些参数进行处理,那么这些参数该如何进行处理呢?

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

转载注明出处:http://www.heiqu.com/dc13eed59dbd9252daded3ed2c115db0.html