每當在Node.js中遇到Buffer,Stream和binary data之類的單詞時,是否老是像我同樣感到困惑? 認爲它們並非經常使用的,而只適合Node.js專家和包開發人員去使用。html
實際上,這些單詞是很是重要的,尤爲對於用Node.js進行web開發而沒有任何CS學位的人員。node
固然,若是你選擇繼續作一個普通的Node.js開發人員,你可能永遠不會直接使用它們。可是若是你想對Node.js的理解提高到下一個級別,那麼你確實須要更深刻地瞭解Node的許多核心特性。好比Buffer。這正是我寫這篇文章的目的——幫助咱們揭開其中一些特性的神祕面紗,並將Node.js的學習帶到下一個層次。git
在開始前,先看一下Node.js官方文檔對Buffer的說明github
… mechanism for reading or manipulating streams of binary data. The Buffer class was introduced as part of the Node.js API to make it possible to interact with octet streams in the context of things like TCP streams and file system operations.web
讓咱們用簡單易懂的語言來從新描述它:api
Buffer類做爲Node.js API的一部分引入,使操做二進制數據流或與之交互成爲可能。
複製代碼
接下來咱們更深刻的去了解Buffer,streams,binary data。瀏覽器
你可能已經知道計算機以二進制文件存儲和表示數據。二進制就是1和0的集合。例如,下面是5個不一樣的二進制文件,5組不一樣的1和0:併發
10, 01, 001, 1110, 00101011
複製代碼
二進制中每一個1和0都稱爲Bit,這是二進制數字的一種簡短形式。ide
爲了存儲或表示一段數據,計算機須要將該數據轉換爲二進制表示。例如,要存儲數字12,計算機須要將12轉換成二進制表示,即1100。學習
可是在工做中,number並非惟一的數據類型。一般上還會有string,images,videos。計算機知道如何用二進制表示全部的數據類型。好比計算機如何用二進制表示string類型的「L」呢?要將任何字符存儲在二進制文件中,計算機首先將該字符轉換爲數字,而後將該數字轉換爲二進制表示形式。對於字符串「L」,計算機首先將L轉換成表示L的數字。
打開瀏覽器控制檯,輸入「L」. charcodeat(0)。這時控制檯會顯示出數字76,這是字符「L」的數字表示。可是計算機又是如何知道每一個字符表示的確切數字呢?它怎麼知道用76來表示L?
字符集已經定義好的表示每一個字符的確切數字的規則。咱們對這些規則有不一樣的定義,最流行的包括Unicode和ASCII。JavaScript能夠很好地處理Unicode字符集。因此,瀏覽器中的Unicode規定76應該表示L。
咱們已經看到計算機是如何用數字表示字符的。轉換成數字以後計算機再把76轉換它的二進制表示。
正若有一些字符集規則定義數字應該怎麼樣表示字符同樣,也有一些規則定義了數字應該如何在二進制文件中表示。具體來講,就是用多少位來表示數字。這叫作字符編碼。
字符編碼的一個規則是UTF-8。UTF-8聲明字符應該以bytes編碼。一個byte是8位(bit)的集合 —— 8個1和0。所以,UTF-8規定應該使用8個1和0來表示二進制中任何字符。
以前的例子提到,數字12用二進制表示爲 1100,可是用UTF-8表示應該是8位纔對。因此UTF-8規定,計算機須要在不滿8位的二進制數字左邊添加更多的位,以使其成爲一個字節。因此12應該存儲爲00001100。
所以 76 在UTF-8規則下存儲表示爲:01001100
這就是計算機在二進制文件中存儲字符串或字符的方式。一樣,計算機也規定了圖片和視頻應該如何轉換、編碼和存儲在二進制文件中的規則。計算機將全部數據類型存儲在二進制文件中。
如今咱們瞭解了什麼是二進制數據,接下來咱們介紹一下什麼是二進制數據流。
js中的Stream只是表示隨着時間的推移從一個點移動到另外一個點的數據序列。整個概念是,你有大量的數據要處理,可是你不須要等到全部的數據均可用後纔開始處理它。基本上,這個大數據被分解並以塊的形式發送。所以,從Buffer的原始定義來看,這僅僅意味着二進制數據正在文件系統中移動。例如,將存儲在file1.txt中的文本移動到file2.txt。
可是Buffer究竟如何幫助咱們在流與二進制數據進行交互或操做呢?Buffer究竟是什麼?
咱們已經提到,數據流是數據從一個點移動到另外一個點,可是它們到底是如何移動的呢?
一般數據的移動是爲了處理或讀取數據,並根據數據作出決策。在這個過程當中,可能須要數據到達一個最小量或者最大量才能進行處理。所以,若是數據到達的速度快於進程消耗數據的速度,那麼多餘的數據須要在某個地方的等待來處理。另外一方面,若是進程消耗數據的速度快於數據到達的速度,那麼早到達的少數數據須要等待必定數量的數據到達,而後再發送出去進行處理。
那個「等候區」就是Buffer!它是計算機中的一個小物理位置,一般位於RAM中,數據在RAM中被臨時收集、等待,並最終發在流過程當中送出去進行處理。
咱們能夠把整個stream和buffer過程看作一個汽車站。在某個汽車站,汽車直到有必定數量的乘客或者是一個特殊的時間才能夠發車。此外,乘客可能在不一樣的時間以不一樣的速度到達。不管是旅客仍是汽車站都不能控制旅客到達車站的時間。提早到達的乘客須要等汽車發車。當有些乘客到達時,乘客已經滿員或者汽車已經離開,須要等待下一輛汽車。
不管什麼狀況,總有一個等待的地方。這就是Node.js的Buffer! js不能控制數據到達的速度或時間,也不能控制流的速度。它只能決定什麼時候發送數據。若是尚未到時間,Node.js將把它們放在buffer中,即RAM中的一個小位置,直到將它們發送出去進行處理爲止。
一個典型的例子是,當你在觀看流媒體視頻時,能夠看到buffer在工做。若是你的互聯網鏈接足夠快,流的速度將足夠快,能夠當即填滿Buffer併發送出去進行處理,而後再填入另外一個Buffer,而後發送出去,再發送一個,再發送一個,直到流完成爲止。
可是若是你的鏈接很慢,在處理了第一組到達的數據後,視頻會被卡主,這意味着程序正在收集更多的數據,或者等待更多的數據到達。當buffer被填滿並處理後,播放器會繼續播放視頻。在播放的同時,更多的數據將繼續到達並在buffer中等待。
Node.js在處理流期間會自動建立buffer,咱們也能夠經過Nodejs提供的API本身建立buffer。根據你的需求,這裏有幾種不一樣的方法能夠建立buffer。
// Create an empty buffer of size 10.
// A buffer that only can accommodate 10 bytes
const buf1 = Buffer.alloc(10)
// Create a buffer with content
const buf2 = Buffer.from("hello buffer")
複製代碼
當建立成功buffer後,你就能夠開始和它進行交互了。
// 查看buffer的結構
buf1.toJSON()
// { type: 'Buffer', data: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] }
buf2.toJSON()
//{ type: 'Buffer',data: [ 104, 101, 108, 108, 111, 32, 98, 117, 102, 102, 101, 114 ]}
buf1.length // 10
buf2.length // 12
// 寫操做
buf1.write("Buffer really rocks!")
// decode
buf1.toString() // 'Buffer rea'
// 由於buf1建立時只分配了10byte的空間。超過的將不會被存儲。
複製代碼
更多的交互API,能夠查看官方文檔,
但願這篇介紹能幫助您更好地理解Node.js Buffer。
更多有關js的文章,請關注github