当前位置:嗨网首页>书籍在线阅读

10-流

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

20.9 流

在Node中,流是一个很重要的概念。顾名思义,流是用来处理数据的对象(流这个词可能让人联想到流动(flow),由于流动是随着时间的推移而发生的,所以说它是异步的也讲得通)。

流可以是读取流、写入流或者二者结合(统称为流)。只有当数据的流动是随着时间持续发生的,流才有意义。相关的例子可以是敲击键盘事件,或者是一个跟客户端反复交互的web服务器,又或者是文件访问。这些情况下都会用到流(即使现在已经不需要流就可以对文件进行读写了)。接下来会用文件流来演示如何创建一个读取流或者写入流,以及如何通过管道将流连接起来。

第一步,先创建一个写入流,并给它写入一些内容:

const ws = fs.createWriteStream('stream.txt', { encoding: 'utf8' });
ws.write('line 1\n');
ws.write('line 2\n');
ws.end();
end方法有时会接收一个数据类型的参数,这种时候与调用 `write` 是等价的。因此,如果只需要发送一次数据,就可以简单地调用end,把想要传送的数据作为参数传给它。

写入流(ws)可以通过write方法进行写入操作,直到调用end方法,然后流会关闭,在这之后所有调用write方法的地方都会出错。不过,在调用end之前,可以随意调用write方法,写入流是在一段固定时间内写入数据的理想工具。

类似地,可以创建一个读取流,在需要的时候读取数据:

const rs = fs.createReadStream('stream.txt', { encoding: 'utf8' });
rs.on('data', function(data) {
    console.log('>> data: ' + data.replace('\n', '\\n'));
});
rs.on('end', function(data) {
    console.log('>> end');
}); 

在本例中,只是将文件内容打印到控制台中(出于整齐的目的,这里将空行都替换掉)。如果把这两个例子放到同一个文件中:那么就有了一个写入流来写文件,还有一个读取流来读文件。

双向流并不常见,而且也超出了本书的范围。可能就像大家所预期的那样,可以调用write方法来给双向流中写数据,也可以监听双向流上的data和end事件。

由于数据会通过流来“流动”,所以,如果从一个读取流中读出数据,然后立即将数据写进一个写入流,原理上也是可行的。这个过程叫作管道(piping)。比如,可以通过管道将读取流中的内容放入写入流,从而完成文件复制:

const rs = fs.createReadStream('stream.txt');
const ws = fs.createWriteStream('stream_copy.txt');
rs.pipe(ws);

注意本例中不需要特殊编码:因为rs只是从 stream.txt文件中将字节码通过管道传输到ws中(也就是写入stream_copy.txt文件中);只有试图解释数据的时候才需要编码。

管道传输对于流动的数据来说是一个很常见的技术。比如,可以将文件内容通过管道转换成一个webserver的response。或者可以将压缩过的数据传入解压引擎,解压引擎最终会将数据传输到文件写入流中。