流对象Stream学习笔记
不论哪门语言哪个平台,IO读写都是一件很麻烦的事情.想要快速处理IO操作,最佳方案非流对象莫属了.IO操作的对象是什么,是数据,也就是将数据从A点经过处理输送到B点.而stream流从字面上就能看出来流动性,所以将Stream流操作数据的方式按照生活中的水流来理解很容易了.
首先得有水源,数据源就是这个水源.我们需要一个对象来帮助我们得到水源,那么可读流正好就是干这件事的.通过可读流对象的_read()方法一点点的将数据从数据源读取出来(本质是push()方法将数据源一点点推入到水流中)从而为后续的可读流提供源源不断的数据.
其次得有通道,内存就是这里的通道,水的流动也是需要通道的,大的如大江大河,小的如小溪水管.在IO操作中通道就是内存,最好的方式就是如同水流一样,水一点一点的流入通道一点一点的前进最后到达它们的目的地.
最后水流到达目的地,需要一种方式进行获取.如同家里的水龙头,通过它慢慢的获取自来水.正如可写流一样,可以不断的对外提供数据作为输出从而将数据呈现给人们.
所有的流对象都是`EventEmitter`的实例,并且只能操作`Strings`和`Buffer`对象.
流的分类
- 可读流
- 可写流
- 读写流(双工流)
- 转换流(双工流)
可读流
一个用来描述从某个数据源读取数据的抽象对象
模式及工作原理
可读流有两种模式(flowing, paused)
flowing
模式 数据自动从底层系统读取并通过EventEmitter
接口的事件发送给应用程序paused
模式 需要手动执行read()
方法读取数据块
可读流默认都是paused
模式
有三种方式可以转换为
flowing
模式
- 绑定
data
事件 stream.resume()
stream.pipe()
绑定到可写流对象上
有两种方式可以转换为
paused
模式
stream.pause()
stream.unpipe()
可读流的工作原理
创建一个可读流对象,如果使用paused模式,那么就需要手动触发read()方法实现数据读取,也就是调用内部的_read()方法实现数据的读取,默认是按照缓存区方式进行读取
常见可读流对象
- HTTP协议中服务端接收的请求和客户端收到的响应
- FS模块中的文件读取流
- 标准输入流
process.stdin
实现可读流对象
可读流对象是一个抽象对象,那么如何得到具体的可读流对象呢?方法就是自己定义一个类继承自可读流抽象对象,同时实现_read()方法.
可读流API
事件
- data
- readable
如果没有绑定data
事件而是绑定了readable
事件,那么也会执行一次_read()
方法,如果在_read()
方法中调用了push()
方法,就会触发readable
事件,而在readable
事件中可以调用read()
方法获取数据直到最终读取到null
- end
- close
- error
方法
push()
方法调用的是对象内部的_read()
方法
pipe() unpipe()
方法更多是将可读流直接绑定到可写流之上从而实现数据的自动流动
1. push(chunk, encoding)
_read()方法只会调用一次,只有调用push()方法才会再次调用_read()方法
2. read()
3. pipe()
4. unpipe()
5. resume()
6. pause()
7. setEncoding()
可写流
一个用来描述数据将要被写入到某个目的地的抽象对象
常见可写流对象
- HTTP协议中服务端发送的响应和客户端发出的请求
- FS模块中的文件写入流
- 标准输出流
process.stdout
,process.stderr
实现可写流对象
可写流对象是一个抽象对象,那么如何得到具体的可写流对象呢?方法就是自己定义一个类继承自可写流抽象对象,同时实现_write()
或_writev()
方法.
可写流API
事件
- drain
- finish
- pipe
- unpipe
- close
- error
方法
write()
方法调用的是对象内部的_write()
方法
1. write()
2. setDefaultEncoding()
3. end()