[Node.js] Buffer 模組處理

Node.js 的 Buffer 概念,可概念理解為緩衝區,是用來暫時存放輸入、輸出資料的一小塊記憶體。介紹幾種基本的使用方法

定義 Buffer 物件的基本方法 (1)

下方第一行的 0x6e 代表的是 n,相關編碼轉換可於此查詢

var buffer16 = new Buffer([0x6e, 0x6f, 0x64, 0x65, 0x6a, 0x73]); // 基本的 Buffer 宣告方式(預設為16進位編碼),陣列裡存放的資料為 nodejs

// 如果想改用utf8來指定資料的話,就用以下語法:
var bufferUTF8 = new Buffer('nodejs', 'utf8');

console.log("輸出:" + buffer16.length + "."); // 輸出:6
console.log("輸出:" + buffer16 + "."); // 輸出:nodejs

for(var i = 0; i < buffer16.length; i++){
  console.log("輸出:" + buffer16[i]); // 輸出:110 (及相關10進位整數)
  console.log("輸出:" + buffer16[i].toString()); // 輸出:110 (及相關10進位整數)
}

console.log(buffer16.toString('utf8')); // nodejs
console.log(buffer16.toString('hex')); // 6e6f64656a73

上述用了 utf8 及 hex 兩種編碼方式,除此之外,還有 ascii、utf8、utf16le、base64、binary、hex。

定義 Buffer 物件的基本方法 (2)

先定義 Buffer 物件的大小,然後再進行初始化:

var buffer16 = new Buffer(16); // 定義大小為 16
console.log("buffer16's length: " + buffer16.length); // 輸出 16
console.log("buffer16 is : " + buffer16); // 無任何輸出,因為未初始化。
buffer16.write("This is Buffer12", 0, "utf8"); // 初始化寫入資料,第二個參數 0 是 offset 的意思。
console.log("buffer16's length: " + buffer16.length); // 輸出 16,會輸出定義好的大小。
console.log("buffer16 is : " + buffer16); // 正常輸出內容,但若超出定義好的大小的話,會被裁切掉。

使用 Buffer.isBuffer() 方法判斷是否為 Buffer 物件

var buffer = new Buffer('nodejs', 'utf8');
if(Buffer.isBuffer(buffer)){
  console.log("'buffer' is a Buffer obj."); // 此行會輸出。
}else{
  console.log("'buffer' is not a Buffer obj.");
}

var str = "nodejsstring";
if(Buffer.isBuffer(str)){
  console.log("'str' is a Buffer obj.");
}else{
  console.log("'str' is not a Buffer obj."); // 此行會輸出。
}

取得 Buffer 物件位元組長度

Buffer 物件能夠為二進位資料提供很好的支援,那麼取得一個 Buffer 物件真實的位元組長度則是一定會需要的。可使用 Buffer.byteLength() 方法來取得。例如下方程式碼:

var str = '\u00bd + \u00bc = \u00be';
console.log(str + ": " + str.length + " characters, " + Buffer.byteLength(str, 'utf8') + " bytes");

// 輸出結果會是如下圖

\u00bd 表示的是 1/2;
\u00bc 表示的是 1/4;
\u00be 表示的是 3/4。
輸出結果是 9 個字元長度,共佔 12 個 bytes。

讀取 Buffer 物件

var str_readUInt8 = "";
var buf = new Buffer(4);
buf[0] = 0x6;
buf[1] = 0x8;
buf[2] = 0x23;
buf[3] = 0x57;
str_readUInt8 += "buf.readUInt8(i) is : ";
for (i = 0; i < buf.length; i++){
  str_readUInt8 += buf.readUInt8(i).toString(16) + "   ";
}
console.log(str_readUInt8);
// 會輸出如下:
// buf.readUInt8(i) is : 6   8   23   57

除了透過 buf.readUInt8 方法之外,還有 buf.readInt8、buf.readUInt16LE、buf.readInt16LE、buf.readUInt16BE、buf.readInt16BE、buf.readUInt32LE、buf.readInt32LE、buf.readUInt32BE、buf.readInt32BE

寫入 Buffer 物件

var buf = new Buffer(32);
var len = buf.write('\u00bd + \u00bc = \u00be', 0); // 要留意的是,會回傳位元組數。
console.log("buf.write() usage: " + buf.toString("utf8", 0, len) + " , " + len + " bytes");

輸出結果如下圖:

除了 buf.wirte() 之外,尚有 buf.writeUInt8()、buf.writeUInt16BE()、buf.writeUInt16LE()、buf.writeUInt32BE()、buf.writeUInt32LE()。

Buffer 物件轉字串

Buffer 用來直接操作位元組,是比直接操作字串更有效率的,因為省去了 Buffer 物件轉字串的過程。但有時為了方便起見,操作字串還是比較方便些,可透過 buf.toString() 來實作。

var buf = new Buffer(26);
for(var i = 0; i < 26; i++){
  buf[i] = i + 97; // ASCII 中的 97 是 a
}
console.log("buf.toString('ascii'): " + buf.toString('ascii'));
// 輸出:buf.toString('ascii'): abcdefghijklmnopqrstuvwxyz
console.log("buf.toString('ascii', 0, 5): " + buf.toString('ascii', 0, 5));
// 輸出:buf.toString('ascii', 0, 5): abcde
console.log("buf.toString('utf8', 0, 8): " + buf.toString('utf8', 0, 8));
// 輸出:buf.toString('utf8', 0, 8): abcdefgh
console.log("buf.toString('hex', 0, 12): " + buf.toString('hex', 0, 12));
// 輸出:buf.toString('hex', 0, 12): 6162636465666768696a6b6c
console.log("buf.toString(undefined, 0, 18): " + buf.toString(undefined, 0, 18));
// 輸出(當編碼為 undefined 或 null 時,會自動設定為 utf8):buf.toString(undefined, 0, 18): abcdefghijklmnopqr

Buffer 物件的裁切

如果想將一個 Buffer 物件按照需求進行裁切,生成一個新的 Buffer 物件,可使用 buf.slice() 方法來實作。

var buf = new Buffer(26);
for(var i = 0; i < 26; i++){
  buf[i] = i + 97; // ASCII 中的 97 是 a
}
var buf_slice_a = buf.slice(0, 5);
console.log(buf_slice_a.toString('ascii', 0, buf_slice_a.length));
// 輸出:abcde
console.log(buf.toString('ascii', 0, buf.length));
// 輸出:abcdefghijklmnopqrstuvwxyz

由以上可得知,進行 buf.slice() 方法時,並不會影響原來的資料,而是會回傳一個新的 Buffer 物件。

複製 Buffer 物件

使用 buf.copy() 方法:
buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd]);

// 範例 1:
var buf1 = new Buffer(26);
var buf2 = new Buffer(26);

for(var i = 0; i < 26; i++){
  buf1[i] = i + 97; // 97 的 ASCII 是 'a'
  buf2[i] = 35;     // ASCII 是 '#'
}
buf1.copy(buf2, 6, 0, 10);

console.log(buf2.toString('ascii', 0, 25));
// ######abcdefghij#########
console.log(buf1.toString());
// abcdefghijklmnopqrstuvwxyz
// 範例 2:
var buf = new Buffer(26);
for(var i = 0; i < 26; i++){
  buf[i] = i + 97; // 97 的 ASCII 是 'a'
}
console.log(buf.toString());
// abcdefghijklmnopqrstuvwxyz

buf.copy(buf, 0, 6, 10);

console.log(buf.toString());
// ghijefghijklmnopqrstuvwxyz

拼接 Buffer

使用 buf.concat() 方法:
需留意的是,Buffer 其實並不擅於處理字串,因為處理字串的效能較低;相反的,其實它是擅於處理二進位,效能才會較好,在檔案 I/O 和網路 I/O 應用才廣泛。以下是用於處理將陣列裡的字串合併起來,所耗費的時間比較,可得知,使用 Buffer 的效能會較差。

Buffer.concat(list, [totalLength])
參數說明:
list{Array}: 陣列類型,Buffer 陣列,主要是用於被連接。
totalLength: 是整數,代表的是第一個參數 Buffer 陣列物件的總共大小。(不是指陣列長度,是指 Buffer 實例的大小總和。)

var buf = new Buffer("This is Buffer concat test!");
var str = "this is String concat test!";

console.time("buffer concat test!");

var list = [];
var len = 0;

for(var i = 0; i < 100000; i++){
  list.push(buf);
  len += buf.length;
}
var s1 = var s2 = Buffer.concat(list, len).toString();
console.timeEnd("buffer concat test!");

console.time("string concat test!");
var list = [];
for(var i = 100000; i >= 0; i--){
  list.push(str);
}
var s2 = list.join("");
console.timeEnd("string concat test!");

// 以下是輸出結果的時間比較:
// buffer concat test!: 27.325ms
// string concat test!: 11.733ms

您可在此處留言

avatar

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料

  Subscribe  
Notify of