流的作用:
流是一种传输数据的手段,我们知道,读写数据时底层一定是以二进制的形式进行的,这时流要实现对数据传输的控制,应该就表现在数据传输时的大小或者速度上。
那么在什么样的场景下我们们需要控制数据传输的大小和速度呢,或者是什么时候需要用到流这种数据传输方式呢,接下来我们就用几个小例子来进行演示。
假设我们需要从一个文件读取数据到另外一个文件中,
let fs=require('fs');
let data = fs.readFileSync('read.txt');
fs.writeFileSync('write.txt', data);复制代码
可以看到,用nodeJs中读写文件的功能是不是十分简单。我们一次性把数据全部读入到内存中,再写入到目标文件,这过程根本不用流的方式进行控制。可我们得注意一点,我们操作的是这种较小的文本文件,如果面对动辄几个G大小的视频文件,这样一次性读取操作将会极大的占用我们的内存,甚至将内存挤爆。
而流这时就可以发挥它的作用了-控制传输数据的大小。流可以将资源拆分成小块,一块一块的传输,像流水一样,不用先一次性就把所有数据放到内存中,导致内存的消耗。假设这个文本文件很大,我们用nodeJs中的流改写上面的功能。
let readStream=fs.createReadStream('read.txt');
let writeStream=fs.createWriteStream('write.txt');
readStream.on('data',function (chunk) {
//当有数据流入时,就写入数据
writeStream.write(chunk);
});
readStream.on('end',function (chunk) {
//没有数据写入,关闭写入流,读取流默认设置是读取完成自动关闭
writeStream.end();
})复制代码
当然,上面的实现还有些问题,那就是如果读取的速度大于写入的速度,很可能导致数据的丢失,因此,我们可以用流的一个方法pipe
,顾名思义就是管道,它可以控制数据传输速度,让流写完一段数据再读取下一段。如下:
fs.createReadStream('read.txt').pipe(fs.createWriteStream('write.txt'));复制代码
知道了流的作用,我们来看在nodeJs下流的具体实现。
流的实现:
nodeJs中流的功能是由Stream这个基础模块提供的,它也是一个抽象的接口,很多模块都实现了该接口,盗图:
之前我们谈过流可以把资源切块,那这些块是什么呢,它们可以是buffer,string,或者是其它对象,而buffer对象主要用于操作字节,处理二进制数据的,当我们设置流操作的对象是buffer时,这有利于我们的传输速度,因为不用进行其他数据类型的转换,如当需以字符或者其他类型进行呈现数据时。
以上讲解只是用了读取流和写入流做了示例,流还有双工流(Duplex ),转换流(Transform)这两种类型,但都是基于读写流进行组合或者加工而实现的,如双工流就是同时拥有读写两种方法而已。至于这些类型的流是如何通过Stream接口进行实现的,这里就详述了,具体的可以参考下这篇文章:[译] Node.js 流: 你需要知道的一切
参考: