一、Node.js中的stream(流)的概念及作用?
- 什么是流?日常生活中有水流,我们很容易想得到的就是水龙头,那么水龙头流出的水是有序且有方向的(从高处往低处流)。我们在nodejs中的流也是一样的,他们也是有序且有方向的。
- stream:
处理系统缓存的方式
- nodejs中的流是可读的、或可写的、或可读可写的。
并且流继承了EventEmitter。因此所有的流都是EventEmitter的实列。
1.Node.js中有四种基本的流类型:
Readable
–可读的流(比如 fs.createReadStream()).Writable
–可写的流(比如 fs.createWriteStream()).Duplex
–可读写的流Transform
—在读写过程中可以修改和变换数据的Duplex流。
Node.js中的流最大的作用是:读取大文件的过程中,不会一次性的读入到内存中。每次只会读取数据源的一个数据块(收到一个数据,就读取一块,即在数据还没有接收完就开始处理)
。
然后后续过程中可以立即处理该数据块(数据处理完成后会进入垃圾回收机制),而不用等待所有的数据。
2.使用流到底有什么好处呢?
- 文件系统中读取文件的方式
readfile()
,会把 文件内容 整个的读进以 Buffer格式 存入到内存中,然后再写进返回对象,那么这样的效率非常低的,并且该文件如果是1G或2G以上的文件,那么内存会直接被卡死掉的,或者服务器直接会奔溃掉。 - 而使用流的
createReadStream()
方法就可以避免占用内存多的情况发生,在读取大文件的过程中,不会一次性的读入到内存中。每次只会读取数据源的一个数据块,这就是流的优点。
二、常用的流操作
1.读取流
fs.createReadStream()
var fs = require("fs");
var data = '';
// 创建可读流
var readerStream = fs.createReadStream('input.txt');
// 设置编码为 utf8。
readerStream.setEncoding('UTF8');
// 处理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
data += chunk;
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序执行完毕");
2.写入流
fs.createWriteStream()
var fs = require("fs");
var data = '菜鸟教程官网地址:www.runoob.com';
// 创建一个可以写入的流,写入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 编码写入数据
writerStream.write(data,'UTF8');
// 标记文件末尾
writerStream.end();
// 处理流事件 --> finish、error
writerStream.on('finish', function() {
console.log("写入完成。");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序执行完毕");
3.管道流(pipe)
readerStream.pipe(writerStream)
提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中
如上面的图片所示,把文件比作装水的桶,而水就是文件里的内容,我们用一根管子(pipe)连接两个桶使得水从一个桶流入另一个桶,这样就慢慢的实现了大文件的复制过程。
以下实例我们通过读取一个文件内容并将内容写入到另外一个文件中。
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("程序执行完毕");
4.链式流
链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。
- 压缩文件: 创建压缩包
zlib.createGzip()
- 解压文件:
zlib.createGunzip()
接下来我们就是用管道和链式来压缩和解压文件。
- 压缩文件
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("文件压缩完成。");
- 解压文件
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("文件解压完成。");