Node.js Transform 與 Duplex 串流:數據處理的橋樑
除了單向的讀取 (Readable) 與寫入 (Writable),Node.js 還提供了更強大的雙向通訊與資料即時加工工具:Duplex 與 Transform 串流。
Duplex Stream (雙向串流)
Duplex 串流同時實作了 Readable 和 Writable 介面。它的特點是讀取端與寫入端是完全獨立的,資料不會自動從一端流向另一端。
- 經典範例:TCP Socket (
net.Socket)。你可以透過它發送數據,同時也可以接收數據,兩者互不干涉。
Transform Stream (轉換串流)
Transform 是 Duplex 的一種特化版本。它的核心任務是「修改」流經的資料。當資料寫入 Transform 串流後,經過內部處理,再從讀取端推送出來。
- 運作模型:
Input (Writable) -> [處理邏輯] -> Output (Readable) - 經典範例:檔案壓縮 (
zlib)、數據加密 (crypto)。
實戰:利用 zlib 壓縮檔案
const fs = require('fs');
const zlib = require('zlib');
const src = fs.createReadStream('original.txt');
const gzip = zlib.createGzip(); // 這是一個 Transform 串流
const dest = fs.createWriteStream('original.txt.gz');
// 串聯:讀入 -> 壓縮 -> 寫出
src.pipe(gzip).pipe(dest);
dest.on('finish', () => console.log('Gzip 壓縮任務成功完成'));
自定義 Transform 串流
你可以輕鬆地繼承 Transform 類別來實作特定的業務邏輯。例如,將輸入的字串全部轉換為大寫:
const { Transform } = require('stream');
const upperCaseTr = new Transform({
// chunk: 數據塊, encoding: 編碼, callback: 完成後的通知
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
},
// 可選:當所有數據處理完後,清空緩衝區前呼叫
flush(callback) {
this.push('\n--- 轉換處理結束 ---');
callback();
},
});
process.stdin.pipe(upperCaseTr).pipe(process.stdout);
物件模式 (Object Mode)
預設情況下,串流處理的是 Buffer 或 String。但如果你想在串流中傳遞 JavaScript 物件(例如一筆筆 JSON 紀錄),你可以開啟 objectMode。
const objTr = new Transform({
writableObjectMode: true,
readableObjectMode: true,
transform(obj, encoding, callback) {
// 假設輸入是用戶物件,我們只提取名稱
this.push({ name: obj.username.toUpperCase() });
callback();
},
});
串流類型一覽表
| 類型 | 功能 | 代表實例 |
|---|---|---|
| Readable | 只讀取資料 | fs.createReadStream |
| Writable | 只寫入資料 | fs.createWriteStream |
| Duplex | 獨立雙向讀寫 | net.Socket |
| Transform | 修改、轉換資料 | zlib.createGzip, crypto.createHash |
總結
- 如果你需要同時具備讀寫功能但邏輯獨立,用 Duplex。
- 如果你需要對流經的資料進行轉換、壓縮或過濾,用 Transform。
- 善用
objectMode可以讓 Stream 在處理數據庫紀錄時變得極其強大。