Stream是Node.js中非常重要的一个模块,应用广泛。一个流是一个具备了可读、可写或既可读又可写能力的接口,通过这些接口,我们可以和磁盘文件、套接字、HTTP请求来交互,实现数据从一个地方流动到另一个地方的功能。
所有的流都实现了EventEmitter的接口,具备事件能力,通过发射事件来反馈流的状态。比如有错误发生时会发射“error”事件,有数据可被读取时发射“data”事件。这样我们就可以注册监听器来处理某个事件,达到我们的目的。
Node.js定义了Readable、Writable、Duplex、Transform四种流,Node.js有各种各样的模块,分别实现了这些流,我们挑出来一一看一看他们的用法。当然,我们也可以实现自己的流,可以参考Stream的文档或我们即将提到的这些Node.js里的实现。
Readable
Readable流提供了一种将外部来源(比如文件、套接字等)的数据读入到应用程序的机制。
可读的流有两种模式:流动模式和暂停模式。流动模式下,数据会自动从来源流出,跟不老泉似的,直到来源的数据耗尽。暂停模式下,你得通过stream.read()主动去要数据,你要了它才从来源读,你不要它就在那儿耗着等你。
可读流在创建时都是暂停模式。暂停模式和流动模式可以互相转换。
要从暂停模式切换到流动模式,有下面三种办法:
- 给“data”事件关联了一个处理器
- 显式调用resume()
- 调用pipe()将可读流桥接到一个可写流上
要从流动模式切换到暂停模式,有两种途径:
- 如果这个可读的流没有桥接可写流组成管道,直接调用pause()
- 如果这个可读的流与若干可写流组成了管道,需要移除与“data”事件关联的所有处理器,并且调用unpipe()方法断开所有管道。
需要注意的是,出于向后兼容的原因,移除“data”事件的处理器,可读流并不会自动从流动模式转换到暂停模式;还有,对于已组成管道的可读流,调用pause也不能保证这个流会转换到暂停模式。
Readable流的一些常见实例如下:
- 客户端的HTTP响应
- 服务端的HTTP请求
- fs读取流
- zlib流
- crypto(加密)流
- TCP套接字
- 子进程的stdout和stderr
- process.stdin
Readable流提供了以下事件:
- readable:在数据块可以从流中读取的时候发出。它对应的处理器没有参数,可以在处理器里调用read([size])方法读取数据。
- data:有数据可读时发出。它对应的处理器有一个参数,代表数据。如果你只想快快地读取一个流的数据,给data关联一个处理器是最方便的办法。处理器的参数是Buffer对象,如果你调用了Readable的setEncoding(encoding)方法,处理器的参数就是String对象。
- end:当数据被读完时发出。对应的处理器没有参数。
- close:当底层的资源,如文件,已关闭时发出。不是所有的Readable流都会发出这个事件。对应的处理器没有参数。
- error:当在接收数据中出现错误时发出。对应的处理器参数是Error的实例,它的message属性描述了错误原因,stack属性保存了发生错误时的堆栈信息。
Readable还提供了一些函数,我们可以用它们读取或操作流:
- read([size]):如果你给read方法传递了一个大小作为参数,那它会返回指定数量的数据,如果数据不足,就会返回null。如果你不给read方法传参,它会返回内部缓冲区里的所有数据,如果没有数据,会返回null,此时有可能说明遇到了文件末尾。read返回的数据可能是Buffer对象,也可能是String对象。
- setEncoding(encoding):给流设置一个编码格式,用于解码读到的数据。调用此方法后,read([size])方法返回String对象。
- pause():暂停可读流,不再发出data事件
- resume():恢复可读流,继续发出data事件
- pipe(destination,[options])ÿ