Stream 流模块
操作系统采用数据块(chunk)的方式读取数据,每收到一次数据,就存入缓存。
流
Node应用程序有两种缓存的处理方式,第一种是等到所有数据接收完毕,一次性从缓存读取,这就是传统的读取文件的方式(遇上大文件很容易使内存爆仓)*;第二种是采用“数据流”的方式,收到一块数据,就读取一块,即在数据还没有接收完成时,就开始处理它(像流水一样)
基本流
- Readable - 可读的流 (例如
fs.createReadStream()
). - Writable - 可写的流 (例如
fs.createWriteStream()
). - Duplex - 可读写的流 (例如
net.Socket
). - Transform - 在读写过程中可以修改和变换数据的 Duplex 流 (例如
zlib.createDeflate()
).
可读流在创建时都是暂停模式,有暂停模式和流动模式,二者之间可以互相转换
管道流
管道提供了一个输出流到输入流的机制。通常用于从一个流中获取数据并将数据传递到另外一个流中>(把文件比作装水的桶,而水就是文件里的内容,用一根管子(pipe)连接两个桶使得水从一个桶流入另一个桶,这样就慢慢的实现了大文件的复制过程)
链式流
链式是通过连接输出流到另外一个流并创建多个对个流操作链的机制,看起有点像分水器。
下面示例用管道和链式来压缩文件 创建 compress.js 文件
const fs = require("fs");
const zlib = require('zlib')
// 压缩 README.md 文件为 README.md.gz
fs.createReadStream('./README.md')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('README.md.gz'))
console.log("文件压缩完成")
Node事件
所有的流Stream 对象都是 EventEmitter
的实例
data
- 当有数据可读时触发。end
- 没有更多的数据可读时触发。error
- 在接收和写入过程中发生错误时触发。finish
- 所有数据已被写入到底层系统时触发。
流复制
示例演示带进度条显示
const fs = require('fs')
const out = process.stdout
let paths = {
src: '../test.mp4',
dist: '../test1.mp4'
}
function copy(paths){
let {src, dist} = paths
let readStream = fs.createReadStream(src)
let writeStream = fs.createWriteStream(dist)
let stat = fs.statSync(src),
totalSize = stat.size,
progress = 0,
lastSize = 0,
startTime = Date.now()
readStream.on('data', function(chunk) {
progress += chunk.length;
})
// 添加了一个递归的setTimeout来做一个旁观者
// 每500ms观察一次完成进度,并把已完成的大小、百分比和复制速度一并写到控制台上
// 当复制完成时,计算总的耗费时间
setTimeout(function show() {
let percent = Math.ceil((progress / totalSize) * 100)
let size = Math.ceil(progress / 1000000)
let diff = size - lastSize
lastSize = size
out.clearLine()
out.cursorTo(0)
out.write(`已完成${size}MB,${percent}%, 速度:${diff * 2}MB/s`)
if (progress < totalSize) {
setTimeout(show, 500)
} else {
let endTime = Date.now()
console.log(`共用时:${(endTime - startTime) / 1000}秒。`)
}
}, 500)
}
copy(paths)
应用场景
流除了用来处理文件复制。当然还可以用它来处理。
如HTTP requests, on the client、HTTP responses, on the server、 fs write streams、zlib streams、crypto streams、TCP sockets、 child process stdin、 process.stdout
, process.stderr
本作品采用《CC 协议》,转载必须注明作者和本文链接