[Node.js] 串流(stream)應用

在 Node.js 框架中,串流(stream)模組是非常重要的,因為檔案系統(fs)模組每次操作都要將資料全部寫入記憶體,然後再從記憶體取出,這勢必會影響檔案 I/O 操作的速度。故 Node.js 框架提供了一個串流(stream)模組來實現 I/O 操作。

串流(stream)是抽象的概念,可讀、可寫、可雙工(可讀、可寫)。當程式需要從某個資料來源讀入資料的時候,就會開啟一個資料串流,資料來源可以是檔案、記憶體等。相反地,需要寫出資料到某個資料來源目的地的時候,也會開啟一個資料串流,而資料來源目的地也可以是檔案串流、記憶體等。

使用 fs 模組當中的 createReadStream() 方法,建立可讀(readable)串流

var fs = require('fs');

// 建立可讀的串流(readable stream),並設定編碼為 utf8;'data/basic.txt'是 data 資料夾中的一個 basic.txt 檔案。
var rs = fs.createReadStream('data/basic.txt');
rs.setEncoding('utf8');

// 串流模組:data 事件:用於讀取資料區塊的操作。
rs.on('data', function(chunk){
  console.log('串流:接收到資料(data)');
  console.log('讀取到了 %d 位元組的資料。', chunk.length);
  console.log(chunk);

  rs.pause(); // 暫停可讀串流,會使一個處於流動模式的串流停止觸發 data 事件,然後切換到非流動模式,並讓後續的資料留在內部緩衝區中。

  console.log('暫停,設定3秒內不會有資料');
  setTimeout(function(){
    console.log('再次接收資料…');

    rs.resume(); // 恢復可讀串流,繼續觸發 data 事件

    console.log('讀取到的資料:\n', chunk);
  }, 3000);
});

// 串流模組:readable 事件:當一個資料塊(data chunk),可以從串流中被讀出時,則會觸發一個 readable 事件。
rs.on('readable', function(){
  console.log('串流:可讀取(readable)');
});

// 串流模組:error 事件:當資料接收發生錯誤時(例:檔案不存在),會被觸發。
rs.on('error', function(){
  console.log('串流:發生錯誤(error)');
});

// 串流模組:end 事件:當沒有更多資料可以接收時,會觸發此事件。
rs.on('end', function(){
  console.log('串流:結束(end)');
});

// 串流模組:close 事件:當資料來源的串流,被關閉時,會觸發此事件。(註:並非所有串流都會觸發 close 事件)
rs.on('close', function(){
  console.log('串流:關閉串流(close)');
});

使用可讀(Readable)串流發送資料

var stream = require('stream');
var rs = new stream.Readable; // 引入串流(stream)模組

rs.push('Stream測試 '); // 使用 push() 方法發送資料
rs.push('Readable ');
rs.push('Push() ');
rs.push('Pipe() ');

rs.push('\n');
rs.push(null); // 使用 push() 方法,通知發送資料完畢。若沒有通知的話,會發生錯誤。

rs.pipe(process.stdout); // 使用 pipe() 方法匯出資料

輸出結果:
Stream測試 Readable Push() Pipe()

在 readable 事件中讀取檔案裡的資料

var fs = require('fs'); // 引入檔案系統模組
var rs = fs.createReadStream('data/basic.txt'); // 建立可讀(Readable)串流
rs.setEncoding('utf8'); // 設定編碼

rs.on('readable', function(){
  console.log('串流:可讀取(readable)');
  var chunk;
  while(null !== (chunk = rs.read())){
    console.log('得到了 %d 位元組的資料', chunk.length);
    console.log('讀取到的資料:', chunk);
  }
});

rs.read([size]):若有使用 size 參數的話,則可限制每次回傳多少位元組的資料;若沒有使用 size 參數的話,則會回傳緩衝區中的所有資料。

使用 pipe() 方法來複製檔案,也可設定一定時間後關閉 pipe() 串流

var fs = require('fs'); // 引入檔案系統模組
var readable = fs.createReadStream('data/srcFile.txt'); // 建立可讀(Readable)串流
var writable = fs.createWriteStream('data/destFile.txt'); // 建立可寫(Writable)串流

// 所有來自 readable 的資料,都會被寫入到 'data/destFile.txt' 檔中
readable.pipe(writable);

// 設定 1 毫秒後,解除 pipe() 的串流,由於 1 毫秒過短,所以應該會複製不了。
setTimeout(function(){
  readable.unpipe(writable);
  writable.end();
}, 1);

在使用 pipe() 方法複製檔案的過程中,會觸發 data 與 end 事件。
如果 unpipe() 方法沒有指定 writable 的話,所有的 pipe() 都會被解除。

您可在此處留言

搶先留言!

Notify of
avatar
wpDiscuz