Node.js Transform 與 Duplex 串流:數據處理的橋樑

除了單向的讀取 (Readable) 與寫入 (Writable),Node.js 還提供了更強大的雙向通訊與資料即時加工工具:DuplexTransform 串流。

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)

預設情況下,串流處理的是 BufferString。但如果你想在串流中傳遞 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

總結

  1. 如果你需要同時具備讀寫功能但邏輯獨立,用 Duplex
  2. 如果你需要對流經的資料進行轉換、壓縮或過濾,用 Transform
  3. 善用 objectMode 可以讓 Stream 在處理數據庫紀錄時變得極其強大。