作業系統採用資料塊(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 協議》,轉載必須註明作者和本文連結