Like Share Discussion Bookmark Smile

J.J. Huang   2020-01-24   Node.js   瀏覽次數:

Node.js | Stream(流)

簡介

Stream是一個抽象接口,Node中有很多對象實現了這個接口。
例如:對http伺服器發起請求的request對象就是一個Stream,還有stdout(標準輸出)。

Node.js Stream 有四種流類型:

  • Readable:可讀操作。
  • Writable:可寫操作。
  • Duplex:可讀可寫操作.
  • Transform:操作被寫入資料,然後讀出結果。

所有的Stream對像都是EventEmitter的實例。

常用的事件有:

  • data:當有資料可讀時觸發。
  • end:沒有更多的資料可讀時觸發。
  • error:在接收和寫入過程中發生錯誤時觸發。
  • finish:所有資料已被寫入到底層系統時觸發。

註:詳細Doc Link

讀取

input.txt文件,內容如下:

1
J.J.'s Blogs 技術筆記 http://localhost:4000/

main.js,程式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var fs = require("fs");
var data = '';

// 建立可讀流
var readerStream = fs.createReadStream('input.txt');

// 設置編碼為 utf8。
readerStream.setEncoding('UTF8');

// 處理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});

readerStream.on('end',function(){
   console.log(data);
});

readerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("執行完畢");

執行結果如下:

1
2
3
$ node main.js
執行完畢
J.J.'s Blogs 技術筆記 http://localhost:4000/

寫入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var fs = require("fs");
var data = "J.J.'s Blogs 技術筆記 http://localhost:4000/";

// 建立一個可以寫入的流,寫入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');

// 使用 utf8 編碼寫入資料
writerStream.write(data,'UTF8');

// 標記文件末尾
writerStream.end();

// 處理流事件 --> data, end, and error
writerStream.on('finish', function() {
    console.log("寫入完成。");
});

writerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("執行完畢。");

執行結果如下:

1
2
3
$ $ node main.js
執行完畢。
寫入完成。

查看output.txt內容:

1
2
$ cat output.txt
J.J.'s Blogs 技術筆記 http://localhost:4000/%

管道

管道提供了一個輸出流到輸入流的機制。通常我們用於從一個流中獲取資料並將資料傳遞到另外一個流中。

如上面的圖片所示,我們把文件比作裝水的桶,而水就是文件裡的內容,我們用一根管子(pipe)連接兩個桶使得水從一個桶流入另一個桶,這樣就慢慢的實現了大文件的複製過程。

以下實例我們通過讀取一個文件內容並將內容寫入到另外一個文件中。

input.txt文件內容如下:

1
2
J.J.'s Blogs 技術筆記 http://localhost:4000/
管道流操作實例

main.js,程式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
var fs = require("fs");

// 建立一個可讀流
var readerStream = fs.createReadStream('input.txt');

// 建立一個可寫流
var writerStream = fs.createWriteStream('output.txt');

// 管道讀寫操作
// 讀取 input.txt 文件內容,並將內容寫入到 output.txt 文件中
readerStream.pipe(writerStream);

console.log("執行完畢");

程式執行結果如下:

1
2
$ node main.js
執行完畢

查看output.txt文件的內容:

1
2
3
$ cat output.txt
J.J.'s Blogs 技術筆記 http://localhost:4000/
管道流操作實例%

鍊式流

鍊式是通過連接輸出流到另外一個流並建立多個流操作鏈的機制。鍊式流一般用於管道操作。

接下來我們就是用管道和鍊式來壓縮和解壓文件。

壓縮

compress.js,程式如下:

1
2
3
4
5
6
7
8
9
var fs = require("fs");
var zlib = require('zlib');

// 壓縮 input.txt 文件為 input.txt.gz
fs.createReadStream('input.txt')
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream('input.txt.gz'));
  
console.log("文件壓縮完成。");

執行結果如下:

1
2
$ node compress.js
文件壓縮完成。

執行完以上操作後,我們可以看到當前目錄下生成了input.txt的壓縮文件input.txt.gz

解壓該

decompress.js,程式如下:

1
2
3
4
5
6
7
8
9
var fs = require("fs");
var zlib = require('zlib');

// 解壓 input.txt.gz 文件為 input.txt
fs.createReadStream('input.txt.gz')
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream('input.txt'));
  
console.log("文件解壓完成。");

執行結果如下:

1
2
$ node decompress.js
文件解壓完成。

註:以上參考了
Node.js Stream(流)