模块概览

nodejs的核心模块,基本上都是stream的的实例,比如process.stdout、http.clientRequest。

对于大部分的nodejs开发者来说,平常并不会直接用到stream模块,只需要了解stream的运行机制即可(非常重要)。

而对于想要实现自定义stream实例的开发者来说,就得好好研究stream的扩展API了,比如gulp的内部实现就大量用到了自定义的stream类型。

来个简单的例子镇楼,几行代码就实现了读取文件内容,并打印到控制台:

  1. const fs = require('fs');
  2. fs.createReadStream('./sample.txt').pipe(process.stdout);

Stream分类

在nodejs中,有四种stream类型:

  • Readable:用来读取数据,比如 fs.createReadStream()
  • Writable:用来写数据,比如 fs.createWriteStream()
  • Duplex:可读+可写,比如 net.Socket()
  • Transform:在读写的过程中,可以对数据进行修改,比如 zlib.createDeflate()(数据压缩/解压)。

Readable Stream

以下都是nodejs中常见的Readable Stream,当然还有其他的,可自行查看文档。

  • http.IncomingRequest
  • fs.createReadStream()
  • process.stdin
  • 其他

例子一:

  1. var fs = require('fs');
  2. fs.readFile('./sample.txt', 'utf8', function(err, content){
  3. // 文件读取完成,文件内容是 [你好,我是程序猿小卡]
  4. console.log('文件读取完成,文件内容是 [%s]', content);
  5. });

例子二:

  1. var fs = require('fs');
  2. var readStream = fs.createReadStream('./sample.txt');
  3. var content = '';
  4. readStream.setEncoding('utf8');
  5. readStream.on('data', function(chunk){
  6. content += chunk;
  7. });
  8. readStream.on('end', function(chunk){
  9. // 文件读取完成,文件内容是 [你好,我是程序猿小卡]
  10. console.log('文件读取完成,文件内容是 [%s]', content);
  11. });

例子三:

这里使用了.pipe(dest),好处在于,如果源文件较大,对于降低内存占用有好处。

  1. var fs = require('fs');
  2. fs.createReadStream('./sample.txt').pipe(process.stdout);

注意:这里只是原封不动的将内容输出到控制台,所以实际上跟前两个例子有细微差异。可以稍做修改,达到上面同样的效果

  1. var fs = require('fs');
  2. var onEnd = function(){
  3. process.stdout.write(']');
  4. };
  5. var fileStream = fs.createReadStream('./sample.txt');
  6. fileStream.on('end', onEnd)
  7. fileStream.pipe(process.stdout);
  8. process.stdout.write('文件读取完成,文件内容是[');
  9. // 文件读取完成,文件内容是[你好,我是程序猿小卡]

Writable Stream

同样以写文件为例子,比如想将hello world写到sample.txt里。

例子一:

  1. var fs = require('fs');
  2. var content = 'hello world';
  3. var filepath = './sample.txt';
  4. fs.writeFile(filepath, content);

例子二:

  1. var fs = require('fs');
  2. var content = 'hello world';
  3. var filepath = './sample.txt';
  4. var writeStram = fs.createWriteStream(filepath);
  5. writeStram.write(content);
  6. writeStram.end();

Duplex Stream

最常见的Duplex stream应该就是net.Socket实例了,在前面的文章里有接触过,这里就直接上代码了,这里包含服务端代码、客户端代码。

服务端代码:

  1. var net = require('net');
  2. var opt = {
  3. host: '127.0.0.1',
  4. port: '3000'
  5. };
  6. var client = net.connect(opt, function(){
  7. client.write('msg from client'); // 可写
  8. });
  9. // 可读
  10. client.on('data', function(data){
  11. // server: msg from client [msg from client]
  12. console.log('client: got reply from server [%s]', data);
  13. client.end();
  14. });

客户端代码:

  1. var net = require('net');
  2. var opt = {
  3. host: '127.0.0.1',
  4. port: '3000'
  5. };
  6. var client = net.connect(opt, function(){
  7. client.write('msg from client'); // 可写
  8. });
  9. // 可读
  10. client.on('data', function(data){
  11. // lient: got reply from server [reply from server]
  12. console.log('client: got reply from server [%s]', data);
  13. client.end();
  14. });

Transform Stream

Transform stream是Duplex stream的特例,也就是说,Transform stream也同时可读可写。跟Duplex stream的区别点在于,Transform stream的输出与输入是存在相关性的。

常见的Transform stream包括zlibcrypto,这里举个简单例子:文件的gzip压缩。

  1. var fs = require('fs');
  2. var zlib = require('zlib');
  3. var gzip = zlib.createGzip();
  4. var inFile = fs.createReadStream('./extra/fileForCompress.txt');
  5. var out = fs.createWriteStream('./extra/fileForCompress.txt.gz');
  6. inFile.pipe(gzip).pipe(out);

相关链接

https://nodejs.org/api/stream.html