文件操作和網絡都依賴了一個很重要的對象—— Stream, 而這個 <node深入淺出> 沒有分析的,
所以讀完這本書, 在實踐中還會遇到很多困難
stream 是處理 buffer
JavaScript 沒有讀取或者操作二進制數據流的機制。
Buffer 類作為 NodeJS API 的一部分被引入,以便能夠和 TCP 等網絡流和文件流等進行交互。
總而言之,Buffer 類是用來處理二進制數據,
因為太常用了,所以直接放在了全局變量里,使用的時候無需 require。
Buffer 類的實例類似於整型數組,不過緩沖區的大小在創建時確定,不能調整。
Buffer 對象不同之處在於它不經 V8 的內存分配機制,Buffer 是一個 JavaScript 和 C++ 結合的模塊,內存由 C++ 申請,JavaScript 分配。
實例化 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-8、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 中