這篇要進入到資料的世界,認識Buffer(緩衝)與Stream(串流),讓之後要學的通訊協定及資料傳輸能比較好理解。
Buffer(緩衝)是在資料移動時,提供資料暫存的記憶體位置,可以暫時的累積資料再繼續傳遞,就像在網路上看影片時,會有灰色區塊的緩衝暫存還沒播放到的影片資料。
在NodeJS中的緩衝,是以二進制資料(binary data)的形式暫存資料,可以透過函式如:from
或toString
進行資料的解碼或編碼,支援的編碼包含常用的utf8
與ASCII
等,可以參考NodeJS官網的文件說明。
看看例子
new Buffer.from(字串,編碼)
可以直接建立新的Buffer,在定義新的Buffer變數時,編碼預設為utf8
。let buffer = new Buffer.from("Hello"); //編碼預設為utf8
buffer
可以確認Buffer是以二進制資料儲存。console.log(buffer);
toString()
的成果,會將Buffer轉成字串印出。console.log(buffer.toString());
toJSON()
轉成JSON格式物件,Buffer暫存的資料會以unicode編碼的陣列表現。console.log(buffer.toJSON());
Stream(串流)指的是資料傳遞資料的序列流,用具體一點的物質來說明的話,資料和串流就像河流上漂著的東西和河流,資料會順著串流移動,移動至處理資料的目標,在許多情況下也可能會藉由緩衝先暫存部分順著串流移動的資料,再一併傳遞進行資料處理。
在NodeJS中的串流,作為EventEmitter的子類別,繼承了on()
、emit()
等方法,而串流根據資料流向的方向不同又分成writable
(寫入)、readable
(讀取)、duplex
(讀寫)、transform
(轉換)等類型,每一個串流的類別都繼承串流的方法。從官方的文件也可以發現串流的類別是一個抽象/基底類別(abstract/base class),不會被直接使用,而是透過繼承取用的其屬性及方法,因此必須透過建立新的客製化物件再去繼承基底類別。
實作看看
在開始之前,透過lipsum generator製作一份測試用的文字檔案data.txt
。
由於Stream要透過客製化的物件進行繼承,在NodeJS中的fs
模組提供了建立客製化Stream的功能,因此需要引用fs
模組,再透過createReadStream()
建立一個新的讀取串流,在讀取資料時,會先以Buffer的形式暫存。
let fs = require("fs");
let readable = fs.createReadStream(__dirname + "/data.txt"); //__dirname為目前資料夾
on()
註冊data
事件,以監聽資料讀取的過程,而綁定該事件內容的函式,加入chunk
作為讀取資料時的參數,chunk
是串流中傳遞的資料片段,透過印出chunk
可以確認資料讀取的情況。readable.on("data", function(chunk){
console.log(chunk);
});
chunk
二進制成果。createReadStream()
函式中加入編碼,就會以字串印出整份資料。let readable = fs.createReadStream(__dirname + "/data.txt", {encoding: "utf8"});
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);
});
串流(Stream)與緩衝(Buffer)在資料傳遞的概念上很重要,先了解的資料如何移動、暫存的方法,再接下去看到透過通訊傳遞資料的部份時,可以有較深刻的印象。
https://nodejs.org/api/stream.html#stream_stream
https://whien.medium.com/換個角度用生活思考難以理解的串流緩衝區-stream-buffer-66fcb116c70
Learn and Understand NodeJS [課程]