>[success] # 可讀流(Readable)
| API | 描述 |
| --- | --- |
| fs.createReadStream() | 創建可讀文件流 |
| http.IncomingMessage | 處理 http 請求的請求體 |
| process.stdin | 標準輸入流 |
* 關于提供一些方法事件和屬性
| API | 描述 |
| --- | --- |
| `readable.pipe(destination, options)` | 將可讀流與可寫流相連接,使可讀流自動將數據推送到可寫流中,通過可選的`options`參數來支持更多的連接選項。 |
| `readable.push(chunk[, encoding])` | 將新的數據塊放入內部緩存隊列。 |
| `readable.read([size])` | 每次觸發`readable`事件或調用`read()`方法,從內部緩存隊列中返回指定大小的數據塊。如果沒有數據塊可用,則返回`null`。 |
| `readable.resume()` | 恢復可讀流內部的可讀狀態,并觸發`readable`事件。 |
| `readable.setEncoding(encoding)` | 將數據塊轉換為指定的字符編碼。 |
| `readable.pause()` | 暫停可讀流的內部可讀狀態,防止數據繼續讀取和內存占用增加。 |
| `readable.unshift(chunk)` | 將數據塊放回內部緩存隊列頭部。 |
| `readable.wrap(stream)` | 將現有的可讀流轉換為 Node.js 可讀流實例,以便它可以正常與可寫流、管道等相互協同工作。 |
| 事件 | 描述 |
| --- | --- |
| `data` | 當內部緩存隊列中有新的數據塊時觸發。 |
| `readable` | 當可讀流準備好進行讀取操作時觸發。 |
| `end` | 當可讀流讀取完所有數據并且緩存隊列為空時觸發。 |
| `error` | 當發生錯誤時觸發。 |
| 屬性 | 描述 |
| --- | --- |
| `highWaterMark` | 可讀流緩存隊列的最大字節數,該屬性影響可讀流緩存的大小和數據推送的頻率。 |
| `readableState` | 包含實例當前狀態的對象。 |
>[info] ## fs.createReadStream(path\[, options\])
1. `fs.createReadStream`方法來**創建一個可讀流,使用可讀流的方式讀取文件時,數據會被分成小塊逐步讀入內存,而不是一次性讀取整個文件**,
2. 可以通過指定要讀取的文件路徑或者直接使用這個`fd`創建通過`fs.createReadStream`創建`ReadStream`對象
3. 通過`ReadStream`對象,**我們可以從文件中讀取數據,并將其轉換為我們需要的格式。例如,我們可以讀取一個文本文件,并將其轉換為字符串,或者讀取一個二進制文件,并將其轉換為Buffer對象**
4. 創建一個`ReadStream`對象時,它會自動將文件分成一塊塊的數據進行讀取。可以通過設置`highWaterMark`屬性來控制每塊數據的大小。**當我們讀取的數據量超過`highWaterMark`大小時,`ReadStream`對象將自動暫停讀取**,等待我們處理已經讀取的數據。當我們處理完數據后,`ReadStream`對象會自動恢復讀取,繼續讀取下一塊數據
5. 當我們不再需要`ReadStream`對象時,應該及時銷毀它,以免造成資源浪費。銷毀`ReadStream`對象后,它會自動關閉文件描述符,觸發'close'事件。如果我們希望在銷毀對象時不觸發'close'事件,可以設置`emitClose`選項為`false`。
6. 一些優缺點對照表
| 優點 | 缺點 |
| --- | --- |
| 內存使用效率高,減少內存使用量 | 實現復雜,需要處理多個事件和回調函數 |
| 速度快,避免一次性將整個文件讀入內存的延遲 | 可讀性差,代碼結構較復雜,可讀性相對較差 |
| 數據處理靈活,可以逐塊處理數據 | 不適合小文件,可能會增加代碼的復雜性,不會帶來很大的性能優勢 |
| 可以控制讀取的范圍,讀取部分內容 | 可靠性差,可能出現數據丟失或不完整,需要處理錯誤和異常情況 |
>[danger] ##### api 說明
1. 默認情況下,`createReadStream`創建的可讀流**會自動關閉**,`api`參數說明,當`options.autoClose`設置為(**默認為true**)`true`時,當讀取流結束時會自動關閉底層文件描述符(file descriptor)或文件句柄(file handle),也就是說,當 **讀取流讀取完所有數據后,底層的文件描述符或文件句柄將被自動關閉**
2. `options.emitClose`設置為(**默認為true**)`true`時,讀取流會在底層文件描述符或文件句柄關閉時觸發 'close' 事件,這個事件觸發后,讀取流的 'close' 事件也會被觸發。如果`options.emitClose`設置為`false`,則不會觸發 'close' 事件。
3. `options.emitClose`設置為`false`,當讀取流結束時,底層的文件描述符或文件句柄仍然會被自動關閉,除非`options.autoClose`設置為`false`。
4. `options.fs`參數是一個可選的文件系統對象,這個參數通常用于測試或開發環境中后續用到在了解
| 參數名 | 類型 | 描述 | 默認值 |
| --- | --- | --- | --- |
| path | string | Buffer | URL |
| options | string | Object | 可選對象,可以包含以下屬性 |
| options.flags | string | 請參閱支持的文件系統標志 | 'r' |
| options.encoding | string | 編碼格式 | null |
| options.fd | integer | FileHandle | 文件描述符 `const readStream = fs.createReadStream(null, { fd })` |
| options.mode | integer | 文件的權限掩碼 | 0o666 |
| options.autoClose | boolean | 自動關閉標志 | true |
| options.emitClose | boolean | 關閉事件標志 | true |
| options.start | integer | 起始位置(以字節為單位) | 0 |
| options.end | integer | 結束位置(以字節為單位) | Infinity |
| options.highWaterMark | integer | 每次讀取的最大字節數 | 64 \* 1024 |
| options.fs | Object | null | 文件系統對象 |
>[danger] ##### 案例
| **事件** | **描述** |
| --- | --- |
| `data` | 當流讀取到數據時觸發。 |
| `end` | 當流讀取完所有數據時觸發。 |
| `error` | 當流發生錯誤時觸發。 |
~~~
const fs = require('fs')
// 1. 獲取readStream 流
const stream = fs.createReadStream('./b.txt')
console.log(12)
// 2. 監聽流的data事件
stream.on('data', (chunk) => {
console.log(chunk.toString())
})
// 3. 監聽流的end事件
stream.on('end', () => {
console.log('end')
})
// 4. 監聽流的error事件
stream.on('error', (err) => {
console.log(err)
})
// 5. 監聽流的close事件
stream.on('close', () => {
console.log('close')
})
// 6. 監聽流的open事件
stream.on('open', () => {
console.log('open')
})
~~~
* 使用 fd 讀取文件
~~~
const fs = require('fs')
const fd = fs.openSync('./a.txt')
// 1. 獲取readStream 流
const stream = fs.createReadStream(null, { fd, highWaterMark: 3 })
console.log(12)
// 2. 監聽流的data事件
stream.on('data', (chunk) => {
console.log(chunk.toString())
})
// 3. 監聽流的end事件
stream.on('end', () => {
console.log('end')
})
// 4. 監聽流的error事件
stream.on('error', (err) => {
console.log(err)
})
// 5. 監聽流的close事件
stream.on('close', () => {
console.log('close')
})
// 6. 監聽流的open事件
stream.on('open', () => {
console.log('open')
})
~~~
>[danger] ##### 案例二
| **方法** | **描述** |
| --- | --- |
| `pause()` | 用于暫停可讀流的數據讀取,調用該方法后,可讀流將不會再觸發 'data' 事件,直到調用`resume()`方法恢復數據讀取。該方法通常用于暫停數據讀取,以便進行某些操作或等待其他事件發生。 |
| `resume()` | 用于恢復可讀流的數據讀取,調用該方法后,可讀流將繼續觸發 'data' 事件,從而讀取數據。該方法通常用于恢復數據讀取,以便繼續處理數據。 |
| `pipe()` | 用于將一個**可讀流**連接到一個**可寫流**,將**可讀流中的數據輸出到可寫流中**。該方法會自動管理數據流動,從而實現高效的數據傳輸。該方法還可以接收一個可選的參數,用于控制數據傳輸的方式和行為,例如是否自動關閉可寫流、是否允許多個可寫流等 |
| `unpipe()` | 用于停止將可讀流中的數據輸出到另一個可寫流中,取消數據傳輸。可以將一個可寫流對象作為參數傳遞給該方法,表示只取消將指定的可寫流對象中的數據輸出,如果不傳遞參數,則表示取消所有的數據輸出。該方法通常用于在數據傳輸過程中動態取消數據輸出,以便進行其他操作或處理錯誤。 |
* 關于方法使用,這里只是列舉部分更多詳細需要看`ReadStream`api
* * *
用可讀流和可寫流壓縮文件
~~~
const fs = require('fs');
const zlib = require('zlib');
const readableStream = fs.createReadStream('source.txt');
const gzipStream = zlib.createGzip();
const writableStream = fs.createWriteStream('destination.txt.gz');
readableStream.pipe(gzipStream).pipe(writableStream);
~~~
使用`fs`模塊的`createReadStream`方法創建可讀流對象`readableStream`,并將其指向源文件`source.txt`。然后,我們在`data`事件中調用`pause`方法暫停數據讀取,并在 1 秒鐘后調用`resume`方法恢復數據讀取
~~~
const fs = require('fs');
const readableStream = fs.createReadStream('source.txt');
readableStream.on('data', (chunk) => {
console.log(chunk.toString());
readableStream.pause();
setTimeout(() => {
readableStream.resume();
}, 1000);
});
~~~
使用 unpipe 方法取消數據輸出,`fs`模塊的`createReadStream`方法創建可讀流對象`readableStream`,并將其指向源文件`source.txt`。同時,我們使用`createWriteStream`方法創建兩個可寫流對象`writableStream1`和`writableStream2`,并將其分別指向兩個目標文件`destination1.txt`和`destination2.txt`。然后,我們使用`pipe`方法將可讀流和兩個可寫流連接起來,將源文件中的數據拷貝到兩個目標文件中。最后,我們在 1 秒鐘后調用`unpipe`方法取消了其中一個數據輸出流的連接,即將可讀流和`writableStream1`的連接斷開,使得數據只輸出到`writableStream2`中
~~~
const fs = require('fs');
const readableStream = fs.createReadStream('source.txt');
const writableStream1 = fs.createWriteStream('destination1.txt');
const writableStream2 = fs.createWriteStream('destination2.txt');
const pipe1 = readableStream.pipe(writableStream1);
const pipe2 = readableStream.pipe(writableStream2);
setTimeout(() => {
readableStream.unpipe(pipe1);
}, 1000);
~~~
- 基礎
- 什么是Node.js
- 理解 I/O 模型
- 理解node 中 I/O
- 對比node 和java 使用場景
- node 模塊管理
- 內置模塊 -- buffer
- 內置模塊 -- fs
- fs -- 文件描述符
- fs -- 打開文件 api
- fs -- 文件讀取 api
- fs -- 文件寫入 api
- fs -- 創建目錄 api
- fs -- 讀取文件目錄結構 api
- fs -- 文件狀態(信息) api
- fs -- 刪除文件/目錄 api
- fs -- 重命名 api
- fs -- 復制文件 api
- 內置模塊 -- events
- 內置模塊 -- stream
- 可讀流 -- Readable
- 可寫流 -- Writable
- Duplex
- Transform
- 內置模塊 -- http
- http -- 從客戶端發起
- http -- 從服務端發起
- 內置模塊 -- url
- 網絡開發