Stream

概述

Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对 http 服务器发起请求的 request 对象就是一个 Stream,还有 stdout(标准输出)也是一个 Stream。

Node.js,Stream 有四种流类型:

  • Readable:可读操作。
  • Writable:可写操作。
  • Duplex:可读可写操作.
  • Transform:操作被写入数据,然后读出结果。

所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

  • data:当有数据可读时触发。
  • end:没有更多的数据可读时触发。
  • error:在接收和写入过程中发生错误时触发。
  • finish:所有数据已被写入到底层系统时触发。

从流中读取数据

读取的基本方法是:通过监听 data 事件,数据会在回调函数的参数中回传。

一个示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var fs = require("fs");
var data = '';

var readerStream = fs.createReadStream('test.txt');
readerStream.setEncoding('UTF8');

// 处理流事件 --> data, end, and error
readerStream.on('data', chunk => { data += chunk; });
readerStream.on('end', () => { console.log(data); });
readerStream.on('error', err => { console.log(err.stack); });

console.log("Done!!");
1
2
3
$ node readstream.js
Done!!
laji shesl's test case

向流中写入数据

写入的基本方法是调用 write 方法。

一个示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var fs = require("fs");
var data = "laji shesl's test case";

var writerStream = fs.createWriteStream('test.txt');

// 处理流事件 --> data, end, and error
writerStream.on('finish', () => { console.log("Finish."); });
writerStream.on('error', (err) => { console.log(err.stack); });

writerStream.write(data,'UTF8');
writerStream.end();

console.log("Done!!");
1
2
3
$ node writestream.js
Done!!
Finish.

查看内容:

1
2
$ cat test.txt
laji shesl's test case%

管道流

这里的管道,与 Unix 设计思想中的管道概念是相同的。它将输入流发送给输出流。

示例程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var fs = require("fs");

var readerStream = fs.createReadStream('input.txt');
var writerStream = fs.createWriteStream('output.txt');

// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);

console.log("Done!!!");

链式流

简单的说链式流就是连续调用管道流,就如同 Unix 中的命令一样。它之所以可以这么做就等同于 C++ 中 << 的返回值原理是一样的。

下面是压缩和解压缩的程序的例子:

1
2
3
4
5
6
7
8
9
var fs = require("fs");
var zlib = require('zlib');

// 压缩 input.txt 文件为 input.txt.gz
fs.createReadStream('input.txt')
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream('input.txt.gz'));
  
console.log("File compose done!!");
1
2
3
4
5
6
7
8
9
var fs = require("fs");
var zlib = require('zlib');

// 解压 input.txt.gz 文件为 input.txt
fs.createReadStream('input.txt.gz')
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream('input.txt'));
  
console.log("File decompose done!!");