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

03-流(Stream)和管道(Pipe)

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

6.2 流(Stream)和管道(Pipe)

流技术贯穿了整个Node核心,为HTTP和其他形式的网络请求提供支持。同时它也为文件系统提供了支持,这也是为什么我在开始深入讲解文件系统模块之前先介绍它。

流对象是一个抽象接口,也就是说你不会直接去创建流,而是跟实现流的对象打交道,比如HTTP请求、文件系统的读写流、ZLib压缩或者 process.stdout 。唯一能真正实现流API的方法是创建一个自定义流。由于这已经超出了本书的范围,所以我会把这部分内容放在后续的练习中。现在,我们来看看其他功能是如何使用流的。

因为Node中有太多对象实现了流接口,所以Node中所有的流都具备以下几个基本功能:

  • 你可以通过 setEncoding 来改变流数据的编码;
  • 你可以检查流是否可读、是否可写,还是两者都可以;
  • 你可以捕获流事件,比如接收数据或关闭连接等事件,并给这些事件分别设置回调函数;
  • 你可以暂停和恢复流;
  • 你可以把一个可读流中的数据通过管道传入一个可写流。

注意那些跟流的读写有关的部分。既需要读也需要写的流称为双工流( duplex )。当输入和输出有因果关联时,双工流也被称为变换(transform)。在本章后面介绍ZLib压缩的章节中,我们会看到这种类型的流。

可读流在创建之后会处于暂停状态,也就是说在显式调用读取的接口( stream. read () )或者恢复接口( stream.resume() )之前,它不会读取任何数据。然而,一旦我们触发数据事件(获取可读流中数据的方式),那么我们使用的流实现(如文件系统的可读流)将切换到流动模式。在流动模式下,数据可以随时被访问并被发送到应用程序。

可读流支持多个事件,但在大多数可读流的应用中,我们只对3个事件感兴趣:数据(data)事件、结束(end)事件和错误(error)事件。当有一个新数据块可用时, data 事件会被发送,当所有数据都被处理后 end 事件会被发送。当然,发生错误时 error 事件会被发送。我们在第5章的例5-1中看到了相关的可读流,我们稍后将在文件系统中再次看到它。

可写流是数据即将被发送(写入)的目的地。我们所需要侦听的事件包括 error 。当 end() 方法被调用、且所有的数据被写入之后,我们需要监听 error 事件和 finish 事件。当尝试写入数据却返回 false 时,还需要监听 drain 事件。在第5章的例5-2中创建一个HTTP客户端时,我们使用了一个可写流,我们还会在第6.3节中看到它与文件系统模块一起使用。

双工流同时具有可读流和可写流的功能。转换流是一种双工流,不同之处在于,与内部输入和输出缓冲器彼此独立存在的双工流不同,转换流直接连接两个流,并在中间加上转换数据的步骤。在代码底层,转换流必须实现一个函数 _transform () ,它接收传入的数据,对数据执行一些操作,然后将操作后的数据输出。

为了更好地理解转换流,我们要仔细了解所有流都具有的功能: pipe() 函数。在例5-1中我们已经见过它了,一个可写流将文件内容直接通过管道传给HTTP响应对象:

// create and pipe readable stream
         var file = fs.createReadStream(pathname);
         file.on("open", function() {
            file.pipe(res);
         });

在这里, pipe() 将文件中的内容(流)拿出来,然后输出到 http.ServerResponse 对象中。在Node文档中,我们知道这个对象实现了可写流的接口,稍后我们会看到 fs.createReadStream() 返回一个 fs.ReadStream ,它是一个可读流的实现。可读流支持的方法之一就是 pipe() 到一个可写流。

后面我们将会详细了解一个使用Zlib模块来压缩文件的例子,不过现在可以先看一眼。下面是一个绝佳的转换流示例。

var gzip = zlib.createGzip();
var fs = require('fs');
var inp = fs.createReadStream('input.txt');
var out = fs.createWriteStream('input.txt.gz');
inp.pipe(gzip).pipe(out);

输入是一个可读流,输出是一个可写流。通过管道将一个流的内容传递给另一个,不过要先经过压缩,这就是转换。