- 新時期的Node.js入門
- 李鍇
- 1506字
- 2019-12-12 17:05:41
2.2 Buffer
Buffer是Node特有(區別于瀏覽器JavaScript)的數據類型,主要用來處理二進制數據,在前端JavaScript中,和二進制數據打交道的機會比較少(ES2015增加了ArrayBuffer類型,用來操作二進制數據流,Node也可以使用該類型,我們會在下一章介紹)。而Node在進行Web開發時經常需要和前端進行數據通信,二進制數據流十分常見(例如傳輸一張gif圖片),因此Node除了String外,還內置了Buffer這一數據類型,它是Node作為運行時對JavaScript做的擴展。
Buffer屬于固有(built-in)類型,因此無須使用require進行引入。
在文件操作和網絡操作中,如果不顯式聲明編碼格式,其返回數據的默認類型就是Buffer。例如下面讀取文件的例子,如果不指定編碼格式,得到的結果就是Buffer字符串。
代碼2.2 讀取一個文件并打印內容

上面的代碼中,最后打印出的是十六進制的數據,由于純二進制格式太長而且難以閱讀,Buffer通常表現為十六進制的字符串。
2.2.1 Buffer的構建與轉換
可以使用Buffer類直接初始化一個Buffer對象,參數可以是由二進制數據組成的數組。

如果想由字符串來得到一個Buffer,同樣可以調用構造函數來實現,例如:

注意:在最新的Node API中,Buffer()方法被標記為Deprecated,表示已經不推薦使用,因為這個方法在某些情況下可能不安全(參考https://github.com/nodejs/node/issues/4660),并且會在將來的版本中將其移除。
目前推薦的是使用Buffer.from方法來初始化一個Buffer對象,上面的代碼可以改寫為如下形式。
代碼2.3 使用Buffer.from來初始化一個Buffer

如果想把一個Buffer對象轉成字符串形式,需要使用toString方法,調用格式為:

Buffer支持的編碼類型種類有限,只有以下6種:
- ASCII
- Base64
- Binary
- Hex
- UTF-8
- UTF-16LE/UCS-2
不過也已經覆蓋了最常用的編碼類型。Buffer還提供了isEncoding方法來判斷是否支持轉換為目標編碼格式。
例如,如果我們想把上一節表示“Hello Node”的Buffer對象轉換為字符串,那么可以調用:

如果toString在調用時不包含任何參數,那么就會默認采用UTF-8編碼,并轉換整個Buffer對象。
2.2.2 Buffer的拼接
在中國古代,有一種詩被稱作回文詩,我們先來看一個例子,如圖2-1所示。

圖2-1
這首詩是北宋秦觀所作,如果不清楚如何斷句,就無法得到正確的詩,正確的斷句:
賞花歸去馬如飛
去馬如飛酒力微
酒力微醒時已暮
醒時已暮賞花歸
Buffer一個常見的使用場景是用來處理HTTP的post請求,隨便在網絡上搜索,都能看到類似如下的代碼。
代碼2.4 使用+=來拼接Buffer

上面的代碼使用+=來拼接上傳的數據流,這個過程包含了一個隱式的編碼轉換。
body+=chunk相當于body+= chunk.toString(),當上傳字符全都是英文的時候固然沒關系,但如果字符串中包含中文或者其他語言,由于toString方法默認使用utf-8編碼,這時就有可能出現亂碼,就像回文詩不按照格式斷句,只會得到幾個不通順的句子一樣。
舉個例子,我們先構造一個中文的字符串,并將其另存為test.txt。

然后我們寫一段代碼來嘗試一下:

highWaterMark
正如其字面意思最高水位線,它表示內部緩沖區最多能容納的字節數,如果超過這個大小,就停止讀取資源文件,默認值是64KB。
假設文件大小為100KB,那么在默認情況下,系統就會每次從文件里讀取64KB大小的數據,隨后觸發data事件;chunk的大小即為highWaterMark的大小;然后接著讀取36KB大小的文件,再次觸發data事件;隨后文件讀取結束,觸發end事件。
如果highWaterMark設置得很小,那么就會發生多次系統調用,這會對性能造成影響。
由于我們要讀取的目標文件很短,因此只設置了10個字節位highWaterMark。
試著運行上面的代碼,得到下面的輸出:

可以看到輸出中產生了亂碼,我們知道utf-8中一個漢字占三個字節,那么我們將highwatermark設置為10后,每三個字之后都會有一個字被截斷,因此在調用toString方法的時候出現了亂碼。讀者也可以將每個chunk的內容打印出來看看,這里不再介紹(樸靈寫的《深入淺出Node.js》一書中用一個章節討論這個問題,建議讀者閱讀一下)。
目前上面的代碼已經被舍棄,官方的推薦做法是使用push方法來拼接Buffer,上面的代碼可改寫成下面形式:
代碼2.5 使用數組來拼接Buffer

上面的代碼在拼接過程中不會有隱式的編碼轉換,首先將Buffer放到數組里面,等待傳輸完成后再進行轉換,這樣就不會出現亂碼了。
- 造個小程序:與微信一起干件正經事兒
- 深入淺出Java虛擬機:JVM原理與實戰
- Python爬蟲開發:從入門到實戰(微課版)
- Selenium Design Patterns and Best Practices
- 琢石成器:Windows環境下32位匯編語言程序設計
- Java程序設計
- 飛槳PaddlePaddle深度學習實戰
- Apache Kafka Quick Start Guide
- Learning ArcGIS for Desktop
- Orchestrating Docker
- Mastering Elixir
- Oracle實用教程
- Flink技術內幕:架構設計與實現原理
- AngularJS UI Development
- HTML5 Canvas核心技術:圖形、動畫與游戲開發