流
stream
是一組有序的,有起點和終點的字節數據傳輸手段,並且有不錯的效率。 藉助事件和非阻塞I/O庫,流模塊容許在其可用的時候動態處理,在其不須要的時候釋放掉。
流stream
是一種在Node.js中處理流式數據的抽象接口。stream
模塊提供瞭如下基礎的API,用於構建實現了流接口對象。 流能夠是可讀、可寫、或是可讀寫的。git
在NodeJS中,咱們對文件的操做須要依賴核心模塊 fs
, fs
模塊中集成了 createReadStream
可讀流。github
fs.createReadStream(path, options)
參數以下:緩存
path
: 讀取的文件路徑bash
options
: string(指定字符編碼) | Object(下面詳細介紹)模塊化
flags
: 標識位,默認爲 'r'encoding
: 字符編碼, 默認爲null,讀取到的值爲Bufferfd
:文件描述符,默認爲 null;mode
:權限位,默認爲 0o666;autoClose
: 讀取完後是否自動關閉,默認爲truestart
: 開始讀取位置,默認0end
: 結束位置,默認文章結束highWaterMark
:// 最高水位線,每次讀多少個。 默認:64*1024 字節返回值爲:fs.ReadStream
函數
// 引入依賴
let fs = require('fs')
let rs = fs.createReadStream('./readStream.txt', {
// start: 0, // 開始讀取位置,默認0
end: 3, // 結束位置,默認文章讀取完
highWaterMark: 3, // 最多讀取, 每次讀取的個數 默認:64*1024 字節
})
複製代碼
在下面例子中
./readStream.txt
的文件內容爲:1234567890
post
open
事件用來監聽文件的打開,回調函數在打開文件後執行。測試
// 引入依賴
let fs = require('fs')
let rs = fs.createReadStream('./readStream.txt', {
start: 0,
end: 3,
highWaterMark: 3
})
// 事件機制,須要本身去監聽一些數據
// open 文件打開
rs.on('open', () => {
console.log('文件開啓了')
})
// 結果:文件開啓了
複製代碼
data
事件,每次讀取 highWaterMark
個字節,就觸發一次該事件,直到讀取完成,回調函數裏面返回的時每次讀取的結果。若是encoding
不設置,則返回爲Bufferui
// 引入依賴
let fs = require('fs')
let rs = fs.createReadStream('./readStream.txt', {
// encoding: 'utf8',
start: 0,
end: 3,
highWaterMark: 3
})
// 事件機制,須要本身去監聽一些數據
// open 文件打開
rs.on('open', () => {
console.log('文件開啓了')
})
rs.on('data', (data) => {
console.log(data)
})
// 若是不是設置encoding返回結果爲
/** 文件開啓了
*<Buffer 31 32 33>
* <Buffer 34>
*/
// 若是encoding: 'utf8'返回結果爲
/** 文件開啓了
* 123
* 4
*/
複製代碼
end
事件,當文件讀取完觸發,並執行回調。編碼
讀取完狀況以下:
end
設置了值( end: 3
),則讀完設置的長度觸發end
沒有設置值,默認讀取完全部內容觸發。爲了方便查看結果,在下面例子中,咱們也實現了這兩種狀況:
// 引入依賴
let fs = require('fs')
let rs = fs.createReadStream('./readStream.txt', {
start: 0,
// end: 3,
highWaterMark: 3
})
// 事件機制,須要本身去監聽一些數據
// open 文件打開
rs.on('open', () => {
console.log('文件開啓了')
})
rs.on('data', (data) => {
console.log(data)
})
rs.on('end', () => {
console.log('結束了')
})
// 設置了end: 3的運行結果
/** 文件開啓了
* <Buffer 31 32 33>
* <Buffer 34>
* 結束了
*/
// 沒有設置end參數的運行結果
/** 文件開啓了
* <Buffer 31 32 33>
* <Buffer 34 35 36>
* <Buffer 37 38 39>
* <Buffer 30>
* 結束了
*/
複製代碼
error
事件監聽錯誤信息,在讀文件出差時觸發回調,並將錯誤信息返回
// error事件 出錯時自動調用
rs.on('error', (err) => {
console.log(err)
})
複製代碼
close
事件用來監聽文件的關閉,回調函數在文件關閉後執行。在建立可讀流時,autoClose: true
(默認值爲true),自動關閉文件,且觸發 close
事件執行回調。
rs.on('close', () => {
console.log('close')
})
複製代碼
可讀流有兩種狀態:流動狀態或暫停狀態兩種。
可讀流開始都時暫停狀態,能夠經過如下方式切換到流動狀態:
data
事件fs.resume()
方法可讀流能夠經過如下方式切換回暫停狀態:
rs.pause()
方法什麼狀況先咱們會用到暫停和恢復呢?
咱們都知道讀取文件會佔用內容空間,若是咱們遇到特別大的文件讀取時,若是所有讀出會佔用很大的內容空間,這不是咱們想要看到的,咱們想到讀取一部分數據,處理完成後再次讀取,就會用到了。
一個簡單的例子
// 引入依賴
let fs = require('fs')
let rs = fs.createReadStream('./readStream.txt', {
encoding: 'utf8', // 字符編碼, 默認爲null
highWaterMark: 2
})
let i = 0
rs.on('data', (data) => {
i ++
console.log(`第 ${i} 次`, new Date());
console.log(data)
rs.pause() // 暫停
setTimeout(() => {
rs.resume() // 恢復
}, 1000)
})
rs.on('end', () => {
console.log('結束了')
})
// 第 1 次 2018-09-16T10:11:00.993Z
// 12
// 第 2 次 2018-09-16T10:11:01.996Z
// 34
// 第 3 次 2018-09-16T10:11:02.997Z
// 56
// 第 4 次 2018-09-16T10:11:03.997Z
// 78
// 第 5 次 2018-09-16T10:11:04.998Z
// 90
// 結束了
複製代碼
在NodeJS中,咱們對文件的操做須要依賴核心模塊 fs
, fs
模塊中集成了 createWriteStream
可讀流
fs.createWriteStream(path, options)
參數以下:
path
: 讀取的文件路徑
options
: string(指定字符編碼) | Object
flags
: 標識位,默認爲 'w'
encoding
: 字符編碼, 默認爲 utf8
fd
:文件描述符,默認爲 null;mode
:權限位,默認爲 0o666;autoClose
: 是否自動關閉,默認爲true
start
: 開始讀取位置,默認0
highWaterMark
: 寫入個數返回值爲:fs.WriteStream
writeStream.txt
文件,表示要寫入內容的文件
// 引入依賴
let fs = require('fs')
let ws = fs.createWriteStream('./writeStream.txt', {
start: 0, // 開始讀取位置,默認0
})
複製代碼
write
在對應的文件寫入內容。end
表示寫入結束,若是後面參數有內容,也是能夠入去到文件。
// 引入依賴
let fs = require('fs')
let ws = fs.createWriteStream('./writeStream.txt', {
start: 0, // 開始寫入位置,默認0
})
ws.write('1') // 寫內容
ws.end('寫完了') // 結束
//結果爲: 1寫完了
複製代碼
可寫流裏面的事件 open
、close
相對對簡單再也不詳述。主要說一下 finish
和 drain
事件.
當調用 ws.end()
方法且緩衝數據都已經傳給底層系統以後,觸發 'finish'
事件。
測試代碼以下:
// 引入依賴
let fs = require('fs')
let ws = fs.createWriteStream('./writeStream.txt', {
start: 0, // 開始寫入位置,默認0
})
ws.on('open', () => {
console.log('open');
});
ws.write('1')
ws.end('寫完了')
ws.on('finish', () => {
console.log('全部寫入已完成。');
});
ws.on('close', () => {
console.error('close');
});
// 輸出結果爲:
// open
// 全部寫入已完成。
// close
複製代碼
若是調用 ws.write(chunk)
方法返回 false
,也就是寫入的內容到達緩存區的大小,觸發 drain
事件
let fs = require('fs')
let ws = fs.createdWriteStream('writeStream.txt', {
start: 0,
highWaterMark: 5
})
// 寫入15個數,每次寫五個,只但願佔用五個字節的內存
let i = 0
function write() {
let flag = true
while(i < 15 && flag) {
flag = ws.write(i++'','utf8')
}
}
write() // 若是寫入的內容到達緩存區的大小了,當他寫入完成後會觸發一個事件
ws.on('drain', () => {
console.log('佔滿')
write() //清空緩存 繼續寫入
})
// 佔滿
// 佔滿
複製代碼
經過 pipe
方式讀取一個文件內容,寫入到另一個文件【經常使用】
// 引入fs模塊
const fs = require("fs");
// 建立可讀流和可寫流
let rs = fs.createReadStream("./ReadStream/readStream.txt", {
highWaterMark: 3
});
let ws = fs.createWriteStream("./writeStream.txt", {
highWaterMark: 2
});
// 將 readStream.txt 的內容經過流寫入 writeStream.txt 中
rs.pipe(ws);
複製代碼
重要:爲了方便你們瞭解、查看、調試代碼,完整的源碼參見gitHub
本篇文章是 NodeJs 中流(stream)的基礎瞭解。但願對你們瞭解流起到必定的做用。
下篇:NodeJS
流的實現原理和簡單實現—— 《流之原,源之理》
未來的你,必定會感謝如今拼命努力的本身!