摘要:閑談系列不涉及具體的講解,只會勾勾畫畫一些自己認為比較重要的特性。我們一般認為用兩個字節(jié)位表示,并且完全囊括了字符集。將其轉(zhuǎn)換成進制就是只是表示它們是碼。三的讀取和寫入相關(guān)重要的只有能夠讀寫,才能夠顯示其存在的價值。
原文地址:http://www.cnblogs.com/DeanCh...
在剛接觸Nodejs的時候,有些概念總讓學前端的我感到困惑(雖然大學的時候也是在搞后端,世界上最好的語言,you know)。我可以很快理解File System,Path等帶有明顯功能的模塊,卻一下子不能理解Buffer這個玄而又玄的東西。因為,在前端的js實踐中,我很少去考慮什么編碼方式,字符集之類的東西。二進制的理解僅限于大學課堂而已。本文與其說是在探討Node的Buffer模塊,倒不如說是來探討下如何從字符集,編碼的角度來理解Buffer這個模塊設立的意義。Node閑談系列不涉及具體的API講解,只會勾勾畫畫一些自己認為比較重要的特性。
一、基本知識正如我們學習編程的第一節(jié)課一樣,我們明白,計算機就是一個二進制生物。它只能理解1和0,或者說有和沒有?!疤珮O生兩儀,兩儀生四象,四象生八卦”。我們在計算上看到的無論是任何東西,都是通過某種特殊的編碼方式,或者說是約定展現(xiàn)出來的。
我們很熟悉的ASCII碼就是這樣一種規(guī)范,和摩爾斯碼一樣,固定的值表示固定的含義。ASCII碼用1個字節(jié)8位來表示2^8=256種狀態(tài)。比如大寫字母A對應的是65,B對應66,是不是很簡單。ASCII碼并不是占滿了所有的256個位置,只用到了一半128位。在一個字節(jié)中,只占用后面7位,最前面一位統(tǒng)一標識為0。
但是我們很容易就發(fā)現(xiàn),ASCII碼遠遠是不夠的,最起碼我們漢字就表示不了。后面考慮了許多其他解決方案,我們在此不多敘述,直接說最終解決方案——Unicode。Unicode想法很直接,就是想把全世界所有的字符都囊括進去。我們一般認為Unicode用兩個字節(jié)16位表示,并且完全囊括了ASCII字符集。比如漢字“好”在unicode里面二進制表示是 0101 1001 0111 1101。將其轉(zhuǎn)換成16進制就是U597D(U只是表示它們是unicode碼)。之所以我前面說是“一般認為”,是因為這種想法是不準確的。Unicode一個平面(plane)是兩個字節(jié)。我們經(jīng)常談論的是它的一個基本平面,編碼是U+0000到U+FFFF,常見字符都在這個平面。Unicode還有16個輔助平面,碼點范圍是U+010000一直到U+10FFFF。一般而言,我們只需要把關(guān)注點放在基本平面就好,并且要習慣Unicode的表示方式。因為,這是畢竟在各種編碼方式間轉(zhuǎn)化的“硬通貨”。
我們常常談到的utf-8,utf-16這些是什么呢?這些都是具體的編碼方式,而Unicode是個字符集。以utf-8為例,它在unicode碼的基礎上,進行重新編碼,把一些本身不需要占滿2個字節(jié)的轉(zhuǎn)化為1個字節(jié)。比如ASCII里面的那些字符,在unicode里面,第一個字節(jié)全是0,簡直是空間的浪費,也會把漢字編碼城3個字節(jié)。你盡可以在控制臺試下Buffer.from("我","utf8")看下編碼后占的字節(jié)數(shù)。
javascript使用哪種編碼方式?
javascript采用Unicode字符集,但是只支持一種編碼方式。那就是USC-2。是不是沒有聽說過?你可以把它理解成utf-16。但它和utf-16到底是什么關(guān)系呢?
兩者的關(guān)系簡單說,就是UTF-16取代了UCS-2,或者說UCS-2整合進了UTF-16。所以,現(xiàn)在只有UTF-16,沒有UCS-2。
UCS-2只支持兩個字節(jié),而在它后面才出來的UTF-16在UCS-2的基礎上,利用輔助平面可以支持4個字節(jié)。既然是UCS-2整合進UTF-16,那就存在有的字符UTF-16有,而UCS-2不存在的情況。出現(xiàn)這種情況怎么辦?大家可以參考下參考資料里面阮老師的講述。
二、Buffer的生成相關(guān)重要的API
Buffer.alloc(size[, fill[, encoding]])
Buffer.allocUnsafe(size)
Buffer.allocUnsafeSlow(size)
Buffer.from(array)
buf.fill(value[, offset[, end]][, encoding])
在Buffer生成的過程中,最大的關(guān)注點就是內(nèi)存的申請和分配。原先new Buffer()生成Buffer的方法已經(jīng)不建議再次使用,它和Buffer.allocUnsafe()方法一樣,可能包含敏感數(shù)據(jù)。
為什么會包含敏感數(shù)據(jù)呢?在生成buffer的過程中,不是一步到位,要分為兩步走,1,申請內(nèi)存空間,2,申請的內(nèi)存空間進行填充。Buffer.allocUnsafe()方法只完成了第一步。不完成第二步的后果就是,申請的空間可能“殘留了”以前內(nèi)存上的數(shù)據(jù)。畢竟一塊兒內(nèi)存在計算機中總是申請了再釋放,釋放了再申請,難免就會導致一些數(shù)據(jù)沒有被及時清理干凈。當然,由于少了第二步操作,速度自然快了不少。
const a = Buffer.allocUnsafe(10); console.log(a) //打印結(jié)果總是不一樣的,但我們發(fā)現(xiàn)每一位上很可能不是00,這些數(shù)據(jù)就屬于敏感數(shù)據(jù)。
可以使用buf.fill(0)進行后期的填充。但為了避免漏洞產(chǎn)生,應該避免使用Buffer.allocUnsafe()來分配內(nèi)存。
Buffer.alloc()比Buffer.allocUnsafe()安全的原因在于它在第二步會把所有的舊數(shù)據(jù)清除掉,填充成0。
const a = Buffer.alloc(10); console.log(a) //打印結(jié)果每一位都是0。
看到這里,你是不是以為Buffer.alloc()和Buffer.allocUnsafe()的區(qū)別僅限于有沒有填充數(shù)據(jù)?其實并不是的。真正與Buffer.alloc()差別在是否填充數(shù)據(jù)的是Buffer.allocUnsafeSlow()。原來,使用Buffer.allocUnsafe()分配內(nèi)存需要借助共享內(nèi)存池(shared internal memory pool)。而Buffer.alloc()和Buffer.allocUnsafeSlow()是直接在內(nèi)存空間上開辟相應大小的內(nèi)存空間。
Buffer.allocUnsafe() (與之前的 new Buffer(size) 機制類似)是三者中分配內(nèi)存速度最快的方式,它采用了共享內(nèi)存池(shared internal memory pool)這一方式,通過預先分配一定大小的一段內(nèi)存,從中再向 JavaScript 分配相應大小的片段,避免頻繁的向系統(tǒng)申請內(nèi)存分配,來達到較高的效率。共享內(nèi)存池的默認值 poolSize 為 8KB(可重新賦值),只有當需要分配的內(nèi)存小于等于 poolSize 的一半時,Buffer.allocUnsafe() 才會從共享內(nèi)存池從分配空間。
這里的知識點到為止,詳細的探討以后可以可以考慮專門寫一篇來說明,參考資料的內(nèi)容也是相當不錯,建議閱讀。
三、Buffer的讀取和寫入相關(guān)重要的API
buf.readInt8(offset[, noAssert])
buf.readDoubleBE(offset[, noAssert])
buf.readDoubleLE(offset[, noAssert])
buf.writeUInt8(value, offset[, noAssert])
buf.writeUInt16BE(value, offset[, noAssert])
buf.writeUInt16LE(value, offset[, noAssert])
...
buffer只有能夠讀寫,才能夠顯示其存在的價值。查看Buffer的文檔,Buffer的讀寫方法中有非常多以“BE”和“LE”結(jié)尾的方法。他們分別代表什么呢?
大字序和小字序
“BE”表示的是“big endian”大端字節(jié)序,而“LE”自然表示“l(fā)ittle endian”小端字節(jié)序。字節(jié)序是干什么的呢?我們在描述一個字符的unicode碼的時候,習慣性地從左到右去寫。為什么不可以從右右往左寫呢?多個字節(jié)無論是讀取還是寫入,總要有一個順序,這就是“字節(jié)序”。大端序就是我們??吹降母呶蛔止?jié)在前,低位字節(jié)在后,小端序恰好相反。
為什么要區(qū)分大端序和小端序呢?不能都統(tǒng)一從一個方向讀取,寫入么?
計算機電路先處理低位字節(jié),效率比較高,因為計算都是從低位開始的。所以,計算機的內(nèi)部處理都是小端字節(jié)序。
但是,人類還是習慣讀寫大端字節(jié)序。所以,除了計算機的內(nèi)部處理,其他的場合幾乎都是大端字節(jié)序,比如網(wǎng)絡傳輸和文件儲存。字節(jié)序的處理,就是一句話:"只有讀取的時候,才必須區(qū)分字節(jié)序,其他情況都不用考慮。"
好,下面我們舉個實際的例子。
var buf = Buffer.from([1,3,5,7]); //buf.readInt16BE(0) //259 從buf中讀取16位的整數(shù),所以讀取的第一個字符對應的碼點是 01 03轉(zhuǎn)化成10進制就是1*16^2+3 = 259。 buf.readInt16LE(0) //756 // 小字序從右往左讀取,第一個字符對應的碼點是 03 01 轉(zhuǎn)化成10進制就是3*16^2+1 = 756
讀取和寫入是一個相反的過程,道理是一樣的。
//官方示例 const buf = Buffer.allocUnsafe(4); buf.writeUInt8(0x3, 0); buf.writeUInt8(0x4, 1); buf.writeUInt8(0x23, 2); buf.writeUInt8(0x42, 3); // Prints:console.log(buf);
Buffer還有很多很有意思的方面需要進一步學習,待以后再進一步補充本文或者寫幾篇相關(guān)更為深入的文章。
未完待續(xù)。。。
參考資料Unicode與JavaScript詳解
字符編碼筆記:ASCII,Unicode 和 UTF-8
Node.js 模塊之 Buffer
Node源碼解析 – buffer
理解字節(jié)序
Buffer/Stream與內(nèi)存管理
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89576.html
摘要:而的主線程中不允許操作網(wǎng)絡,更是將程序員們推向了異步的深淵。異步深淵產(chǎn)生的主要原因是回調(diào),這在里尤其嚴重。為了逃離回調(diào)的深淵,大家開始想各種辦法來把回調(diào)扁平化。目前已經(jīng)在等環(huán)境中得到支持,使用的不僅能大大簡化代碼,還能降低邏輯思路的復雜度。 哦,代碼……就把它們當成插圖吧 隨著 CPU 從單核變多核,軟件從注重功能到注重體驗,Web 從頁面跳轉(zhuǎn)方式到 Web2.0 的無刷新加載(AJA...
摘要:新晉技術(shù)專家下面是墨天輪部分新晉的技術(shù)專家。大家可以點擊往期閱讀墨天輪技術(shù)專家邀請函了解詳情,申請成為我們的技術(shù)專家,加入專家團隊,與我們一起創(chuàng)建一個開放互助的數(shù)據(jù)庫技術(shù)社區(qū)。新關(guān)聯(lián)公眾號墨天輪是一個開放互助的數(shù)據(jù)庫技術(shù)社區(qū)。 引言 近期我們在DBASK小程序增加了數(shù)據(jù)庫 MongoDB、Redis、 Elasticsearch、DB2、Weblogic 等新的的專題欄目和一些新的技術(shù)...
摘要:主要介紹的主要特性和一些經(jīng)驗。先從整體上看一下的一些理念和基本架構(gòu),然后從網(wǎng)絡資源管理存儲服務發(fā)現(xiàn)負載均衡高可用安全監(jiān)控等方面向大家簡單介紹的這些主要特性。集群范圍內(nèi)的監(jiān)控主要由和如構(gòu)建。 主要介紹 Kubernetes 的主要特性和一些經(jīng)驗。先從整體上看一下Kubernetes的一些理念和基本架構(gòu), 然后從網(wǎng)絡、 資源管理、存儲、服務發(fā)現(xiàn)、負載均衡、高可用、rolling upgra...
閱讀 2852·2021-11-19 11:35
閱讀 2596·2021-11-02 14:40
閱讀 1417·2021-09-04 16:48
閱讀 3023·2019-08-30 15:55
閱讀 1779·2019-08-30 13:11
閱讀 1968·2019-08-29 11:12
閱讀 1103·2019-08-27 10:52
閱讀 3173·2019-08-26 18:36