nodeJs中的流是什么?

737 阅读3分钟

流的作用:

流是一种传输数据的手段,我们知道,读写数据时底层一定是以二进制的形式进行的,这时流要实现对数据传输的控制,应该就表现在数据传输时的大小或者速度上。

那么在什么样的场景下我们们需要控制数据传输的大小和速度呢,或者是什么时候需要用到流这种数据传输方式呢,接下来我们就用几个小例子来进行演示。

假设我们需要从一个文件读取数据到另外一个文件中,

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 流: 你需要知道的一切

本文所展示的示例代码

参考:

Node.js Stream(流) 简单易懂全解析

渴望力量吗?少年!流的原理