一,開篇分析
NodeJS的開發語言是JavaScript,JavaScript語言自身只有字符串數據類型,沒有二進制數據類型。NodeJS有時會進行網絡傳輸、文件操作、圖片處理等操作,而這些操作都與二進制數據緊密相關。因此,NodeJS提供了一個與String對等的全局構造函數Buffer來提供對二進制數據的操作。在 Node.js中Buffer 類用來創建一個專門存放二進制數據的緩存區。除了可以讀取文件等操作得到Buffer的實例外,還能夠直接構造。
二、創建 Buffer 類
Buffer 提供了以下 API 來創建 Buffer 類:
- Buffer.alloc(size[, fill[, encoding]]): 返回一個指定大小的 Buffer 實例,如果沒有設置 fill,則默認填滿 0
- Buffer.allocUnsafe(size): 返回一個指定大小的 Buffer 實例,但是它不會被初始化,所以它可能包含敏感的數據
- Buffer.allocUnsafeSlow(size)
- Buffer.from(array): 返回一個被 array 的值初始化的新的 Buffer 實例(傳入的 array 的元素只能是數字,不然就會自動被 0 覆蓋)
- Buffer.from(arrayBuffer[, byteOffset[, length]]): 返回一個新建的與給定的 ArrayBuffer 共享同一內存的 Buffer。
- Buffer.from(buffer): 復制傳入的 Buffer 實例的數據,並返回一個新的 Buffer 實例
- Buffer.from(string[, encoding]): 返回一個被 string 的值初始化的新的 Buffer 實例
三、寫入緩沖區
語法
寫入 Node 緩沖區的語法如下所示:
參數
參數描述如下:
string - 寫入緩沖區的字符串。
offset - 緩沖區開始寫入的索引值,默認為 0 。
length - 寫入的字節數,默認為 buffer.length
encoding - 使用的編碼。默認為 'utf8' 。
根據 encoding 的字符編碼寫入 string 到 buf 中的 offset 位置。 length 參數是寫入的字節數。 如果 buf 沒有足夠的空間保存整個字符串,則只會寫入 string 的一部分。 只部分解碼的字符不會被寫入。
返回值
返回實際寫入的大小。如果 buffer 空間不足, 則只會寫入部分字符串。
實例
執行以上代碼,輸出結果為:
四、從緩沖區讀取數據
語法
讀取 Node 緩沖區數據的語法如下所示:
參數
參數描述如下:
encoding - 使用的編碼。默認為 'utf8' 。
start - 指定開始讀取的索引位置,默認為 0。
end - 結束位置,默認為緩沖區的末尾。
返回值
解碼緩沖區數據並使用指定的編碼返回字符串。
實例
執行以上代碼,輸出結果為:
五、將 Buffer 轉換為 JSON 對象
語法
將 Node Buffer 轉換為 JSON 對象的函數語法格式如下:
當字符串化一個 Buffer 實例時,JSON.stringify() 會隱式地調用該 toJSON()。
返回值
返回 JSON 對象。
實例
執行以上代碼,輸出結果為:
六、聊聊Buffer
JavaScript對字符串處理十分友好,無論是寬字節還是單字節字符串,都被認為是一個字符串。Node中需要處理網絡協議、操作數據庫、處理圖片、文件上傳等,還需要處理大量二進制數據,自帶的字符串遠不能滿足這些要求,因此Buffer應運而生。
Buffer結構
Buffer是一個典型的Javascript和C++結合的模塊,性能相關部分用C++實現,非性能相關部分用javascript實現。
Node在進程啟動時Buffer就已經加裝進入內存,並將其放入全局對象,因此無需require
Buffer對象:類似於數組,其元素是16進制的兩位數。
Buffer內存分配
Buffer對象的內存分配不是在V8的堆內存中,在Node的C++層面實現內存的申請。
為了高效的使用申請來得內存,Node中采用slab分配機制,slab是一種動態內存管理機制,應用各種*nix操作系統。slab有三種狀態:
(1) full:完全分配狀態
(2) partial:部分分配狀態
(3) empty:沒有被分配狀態
七、總結
(1)JavaScript適合處理Unicode編碼數據,但對二進制數據的處理並不友好。
(2)所以處理TCP流或文件系統時,對八位字節流的處理很有必要。
(3)Node有幾個用於處理,創建和消耗八位字節流的方法。
(4)原始數據存放在一個Buffer實例中,一個Buffer類似一個整數數組,但是它的內存,分配在V8堆棧外。一個Buffer的大小是不能更改的。
(5)處理的編碼類型有:ascii,utf8,utf16le,ucs2(utf16le的別名),base64,binary,hex。
(6)Buffer為全局元素,直接new Buffer()就得到一個Buffer實例。