流(stream)在 Node.js 中是處理流數(shù)據(jù)的抽象接口(abstract interface)。 stream 模塊提供了基礎的 API 。使用這些 API 可以很容易地來構建實現(xiàn)流接口的對象。從程序角度而言流是有方向的數(shù)據(jù),簡單的說 流 就是數(shù)據(jù)的加工操作與傳遞。
nodejs中關于 流 的操作都封裝的 stream 模塊中。
Node.js,Stream 有四種流類型:
Readable - 可讀操作。
Writable - 可寫操作。
Duplex - 可讀可寫操作.
Transform - 操作被寫入數(shù)據(jù),然后讀出結果。
所有的 Stream 對象都是 EventEmitter 的實例。常用的事件有:
data - 當有數(shù)據(jù)可讀時觸發(fā)。
end - 沒有更多的數(shù)據(jù)可讀時觸發(fā)。
error - 在接收和寫入過程中發(fā)生錯誤時觸發(fā)。
finish - 所有數(shù)據(jù)已被寫入到底層系統(tǒng)時觸發(fā)。
1.復制文件數(shù)據(jù)
fs接口:用于與文件系統(tǒng)進行交互,所有文件的系統(tǒng)操作都有同步和異步兩種方式。
fs.createReadStream(path[, options])和readFiles的區(qū)別:
createReadStream是給你一個ReadableStream,你可以聽它的'data',一點一點兒處理文件,用過的部分會被GC,所以占內存少。
readFile是把整個文件全部讀到內存里。
const fs = require('fs');//文件系統(tǒng)模塊
// 創(chuàng)建可讀流
const rs = fs.createReadStream('hello.txt');
//創(chuàng)建可寫操作流程
const ws = fs.createWriteStream('./result/result.txt');
將rs的內容結果復制進ws下的文件內
rs.pipe(ws);
有個值得注意地方:數(shù)據(jù)必須是從上游 pipe 到下游,也就是從一個 readable 流 pipe 到 writable 流。
2.為什么應該使用 Stream
有個用戶需要在線看視頻的場景,假定我們通過 HTTP 請求返回給用戶電影內容,那么代碼可能寫成這樣
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
fs.readFile(moviePath, (err, data) => {
res.end(data);
});
}).listen(8080);
http.createServer([requestListener])
由于該方法屬于http模塊,使用前需要引入http模塊(var http= require(“http”) )。
該函數(shù)用來創(chuàng)建一個HTTP服務器,并將 requestListener 作為 request 事件的監(jiān)聽函數(shù)
以上的代碼會造成2個問題
1.電影文件需要讀完之后才能返回給客戶,等待時間超長
2.電影文件需要一次放入內存中,相似動作多了,內存吃不消
用流可以講電影文件一點點的放入內存中,然后一點點的返回給客戶(利用了 HTTP 協(xié)議的 Transfer-Encoding: chunked 分段傳輸特性),用戶體驗得到優(yōu)化,同時對內存的開銷明顯下降
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
fs.createReadStream(moviePath).pipe(res);
}).listen(8080);