iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0
自我挑戰組

學習NodeJS的30天系列 第 9

Day9 NodeJS-Buffer與Stream

這篇要進入到資料的世界,認識Buffer(緩衝)與Stream(串流),讓之後要學的通訊協定及資料傳輸能比較好理解。

Buffer

Buffer(緩衝)是在資料移動時,提供資料暫存的記憶體位置,可以暫時的累積資料再繼續傳遞,就像在網路上看影片時,會有灰色區塊的緩衝暫存還沒播放到的影片資料。

https://ithelp.ithome.com.tw/upload/images/20210924/20139980wwuc4Ihg1q.jpg

在NodeJS中的緩衝,是以二進制資料(binary data)的形式暫存資料,可以透過函式如:fromtoString進行資料的解碼或編碼,支援的編碼包含常用的utf8ASCII等,可以參考NodeJS官網的文件說明。

看看例子

  1. 由於Buffer在資料串流上經常使用,因此NodeJS將Buffer定義為全域參數,不需再另外引用,以new Buffer.from(字串,編碼)可以直接建立新的Buffer,在定義新的Buffer變數時,編碼預設為utf8
let buffer = new Buffer.from("Hello");		//編碼預設為utf8
  1. 直接印出buffer可以確認Buffer是以二進制資料儲存。
console.log(buffer);

https://ithelp.ithome.com.tw/upload/images/20210924/20139980GeTls6U7gq.png

  1. 另外嘗試印出使用toString()的成果,會將Buffer轉成字串印出。
console.log(buffer.toString());

https://ithelp.ithome.com.tw/upload/images/20210924/20139980pJCeCYWTsU.png

  1. 除了字串也可以透過toJSON()轉成JSON格式物件,Buffer暫存的資料會以unicode編碼的陣列表現。
console.log(buffer.toJSON());

https://ithelp.ithome.com.tw/upload/images/20210924/20139980Y5WKATMlDU.png

Stream

Stream(串流)指的是資料傳遞資料的序列流,用具體一點的物質來說明的話,資料和串流就像河流上漂著的東西和河流,資料會順著串流移動,移動至處理資料的目標,在許多情況下也可能會藉由緩衝先暫存部分順著串流移動的資料,再一併傳遞進行資料處理。

https://ithelp.ithome.com.tw/upload/images/20210924/201399800lNjzL9wab.jpg

在NodeJS中的串流,作為EventEmitter的子類別,繼承了on()emit()等方法,而串流根據資料流向的方向不同又分成writable(寫入)、readable(讀取)、duplex(讀寫)、transform(轉換)等類型,每一個串流的類別都繼承串流的方法。從官方的文件也可以發現串流的類別是一個抽象/基底類別(abstract/base class),不會被直接使用,而是透過繼承取用的其屬性及方法,因此必須透過建立新的客製化物件再去繼承基底類別。

https://ithelp.ithome.com.tw/upload/images/20210924/20139980ytbNGsxSha.jpg

實作看看

  1. 在開始之前,透過lipsum generator製作一份測試用的文字檔案data.txt

  2. 由於Stream要透過客製化的物件進行繼承,在NodeJS中的fs模組提供了建立客製化Stream的功能,因此需要引用fs模組,再透過createReadStream()建立一個新的讀取串流,在讀取資料時,會先以Buffer的形式暫存。

let fs = require("fs");

let readable = fs.createReadStream(__dirname + "/data.txt");	//__dirname為目前資料夾
  1. 使用on()註冊data事件,以監聽資料讀取的過程,而綁定該事件內容的函式,加入chunk作為讀取資料時的參數,chunk是串流中傳遞的資料片段,透過印出chunk可以確認資料讀取的情況。
readable.on("data", function(chunk){
  console.log(chunk);
});
  1. 執行除錯後,由於Stream中的Buffer尺寸預設為64KB,因此一次性的印出大小61150bytes的chunk二進制成果。

https://ithelp.ithome.com.tw/upload/images/20210924/20139980k1nzOLSS9W.png

  1. 若想以字串的形式檢視成果,可以在createReadStream()函式中加入編碼,就會以字串印出整份資料。
let readable = fs.createReadStream(__dirname + "/data.txt", {encoding: "utf8"});

https://ithelp.ithome.com.tw/upload/images/20210924/2013998005BueTRbPd.png

  1. Buffer的大小也可透過highWaterMark設定,單位為bytes。這邊以32KB作為例子,另外將印出的資訊改為chunk.length確認資料是否因Buffer尺寸變動而分段。
let readable = fs.createReadStream(__dirname + "/data.txt", {encoding: "utf8", highWaterMark: 32*1024});

readable.on("data", function(chunk){
  console.log(chunk.length);
});

https://ithelp.ithome.com.tw/upload/images/20210924/20139980jOPSZAIVo9.png

小結

串流(Stream)與緩衝(Buffer)在資料傳遞的概念上很重要,先了解的資料如何移動、暫存的方法,再接下去看到透過通訊傳遞資料的部份時,可以有較深刻的印象。

參考資料

https://nodejs.org/api/stream.html#stream_stream

https://whien.medium.com/換個角度用生活思考難以理解的串流緩衝區-stream-buffer-66fcb116c70

Learn and Understand NodeJS [課程]


上一篇
Day8 NodeJS-libuv與Asynchonous
下一篇
Day10 NodeJS-Pipe
系列文
學習NodeJS的30天30

尚未有邦友留言

立即登入留言