NodeJS stream 一:Buffer

當年是看了樸靈的九淺一深 NodeJS 入門的 Node, 樸大大的書講實踐不多更多的篇幅用在了講原理上,道理聽了那麼多,後來開始在前端工程領域使用 NodeJS 卻到處掣肘,總結緣由發現 NodeJS 中難的部分無非是文件和網絡,文件操做和網絡都依賴了一個很重要的對象—— Stream,這偏偏是樸大大書中沒有說起的。javascript

Buffer 樸大大在書中是有提到過的,但由於流實際上就是在處理 Buffer,因此仍是要簡單總結一下。html

什麼是 Buffer

如同官方 API 中介紹的那樣,在 ES6 引入 TypedArray 以前,JavaScript 沒有讀取或者操做二進制數據流的機制。 Buffer 類做爲 NodeJS API 的一部分被引入,以便可以和 TCP 等網絡流和文件流等進行交互。前端

如今 TypedArray 已經被添加到了 ES6 中,Buffer 類以一種更優化和適用於 NodeJS 操做的方式實現了 Unit8Array API。java

總而言之,Buffer 類是用來處理二進制數據,由於太經常使用了,因此直接放在了全局變量裏,使用的時候無需 require。node

Buffer 類的實例相似於整型數組,不過緩衝區的大小在建立時肯定,不能調整。Buffer 對象不一樣之處在於它不經 V8 的內存分配機制,Buffer 是一個 JavaScript 和 C++ 結合的模塊,內存由 C++ 申請,JavaScript 分配。api

關於 Buffer 內存分配相關知識不展開討論,感興趣同窗能夠看看樸老溼的書。數組

實例化 Buffer

在 NodeJS v6 以前都是經過調用構造函數的方式實例化 Buffer,根據參數返回不一樣結果。處於安全性緣由,這種方式在 v6 後的版本中已經被廢除,提供了安全

  • Buffer.from()
  • Buffer.alloc()
  • Buffer.allocUnsafe()

三個單獨的,職責清晰的函數處理實例化 Buffer 的工做。網絡

  • Buffer.from(array):返回一個內容包含所提供的字節副本的 Buffer,數組中每一項是一個表示八位字節的數字,因此值必須在 0 ~ 255 之間,不然會取模
  • Buffer.from(arrayBuffer):返回一個與給定的 ArrayBuffer 共享內存的新 Buffer
  • Buffer.from(buffer):返回給定 Buffer 的一個副本 Buffer
  • Buffer.from(string [, encoding]):返回一個包含給定字符串的 Buffer
  • Buffer.alloc(size [, fill [, encoding]]):返回指定大小而且「已填充」的 Buffer
  • Buffer.allocUnsafe(size):返回指定大小的 Buffer,內容必須用 buf.fill(0) 等方法填充
// 0x 表示 16 進制

Buffer.from([1, 2, 3]) // [0x1, 0x2, 0x3]

Buffer.from('test', 'utf-8') // [0x74, 0x65, 0x73, 0x74]

Buffer.alloc(5, 1) // [0x1, 0x1, 0x1, 0x1, 0x1]

Buffer.allocUnsafe(5); // 值不肯定,後面詳談

Buffer.allocUnsafe() 的執行會快於 Buffer.alloc() 看名字很不安全,確實也不安全。函數

當調用 Buffer.allocUnsafe() 時分配的內存段還沒有初始化(不歸零),這樣分配內存速度很塊,但分配到的內存片斷可能包含舊數據。若是在使用的時候不覆蓋這些舊數據就可能形成內存泄露,雖然速度快,儘可能避免使用。

編碼

Buffer 支持如下幾種編碼格式

  • ascii
  • utf8
  • utf16le
  • base64
  • binary
  • hex

Buffer 和 String 轉換

字符串轉爲 Buffer 比較簡單

Buffer.from(string [, encoding])

同時 Buffer 實例也有 toString 方法將 Buffer 轉爲字符串

buf.toString([encoding[, start[, end]]])

Buffer 拼接

使用 concat 方法能夠講多個 Buffer 實例拼接爲一個 Buffer 實例

Buffer.concat(list[, totalLength])

StringDecoder

在 NodeJS 中一個漢字由三個字節表示,若是咱們處理中文字符的時候使用了不是3的倍數的字節數就會形成字符拼接亂碼問題。

const buf = Buffer.from('中文字符串!');

for(let i = 0; i < buf.length; i+=5){
  var b = Buffer.allocUnsafe(5);
  buf.copy(b, 0, i);
  console.log(b.toString());
}

這樣能夠看到結果中出現了亂碼

但若是使用 string_decoder 模塊即可以解決這個問題

const StringDecoder = require('string_decoder').StringDecoder;
const decoder = new StringDecoder('utf8');

const buf = Buffer.from('中文字符串!');

for(let i = 0; i < buf.length; i+=5){
  var b = Buffer.allocUnsafe(5);
  buf.copy(b, 0, i);
  console.log(decoder.write(b));
}

StringDecoder 在獲得編碼後,知道寬字節在utf-8下佔3個字節,因此在處理末尾不全的字節時,會保留到第二次 write()。目前只能處理UTF-八、Base64 和 UCS-2/UTF-16LE。

Buffer 其它經常使用 API

還有一些 Buffer 經常使用的 API

  • Buffer.isBuffer:判斷對象是否爲 Buffer
  • Buffer.isEncoding:判斷 Buffer 對象編碼
  • buf.length:返回 內存爲此 Buffer 實例所申請的字節數,並非 Buffer 實例內容的字節數
  • buf.indexOf:和數組的 indexOf 相似,返回某字符串、acsii 碼或者 buf 在改 buf 中的位置
  • buf.copy:將一個 buf 的(部分)內容複製到另一個 buf 中
相關文章
相關標籤/搜索