国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

NodeJS中Buffer模塊詳解

2019-11-20 13:28:30
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

一,開(kāi)篇分析

所謂緩沖區(qū)Buffer,就是 "臨時(shí)存貯區(qū)" 的意思,是暫時(shí)存放輸入輸出數(shù)據(jù)的一段內(nèi)存。

JS語(yǔ)言自身只有字符串?dāng)?shù)據(jù)類型,沒(méi)有二進(jìn)制數(shù)據(jù)類型,因此NodeJS提供了一個(gè)與String對(duì)等的全局構(gòu)造函數(shù)Buffer來(lái)提供對(duì)二進(jìn)制數(shù)據(jù)的操作。除了可以讀取文件得到Buffer的實(shí)例外,還能夠直接構(gòu)造,例如:

復(fù)制代碼 代碼如下:

 var buffer = new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]) ;

Buffer與字符串類似,除了可以用.length屬性得到字節(jié)長(zhǎng)度外,還可以用[index]方式讀取指定位置的字節(jié),例如:

復(fù)制代碼 代碼如下:

buffer[0] ; // 0x68;

Buffer與字符串能夠互相轉(zhuǎn)化,例如可以使用指定編碼將二進(jìn)制數(shù)據(jù)轉(zhuǎn)化為字符串:

復(fù)制代碼 代碼如下:

var str = buffer.toString("utf-8");  // hello

將字符串轉(zhuǎn)換為指定編碼下的二進(jìn)制數(shù)據(jù):

復(fù)制代碼 代碼如下:

var buffer= new Buffer("hello", "utf-8") ; // <Buffer 68 65 6c 6c 6f>

一點(diǎn)兒區(qū)別:

Buffer與字符串有一個(gè)重要區(qū)別。字符串是只讀的,并且對(duì)字符串的任何修改得到的都是一個(gè)新字符串,原字符串保持不變。

至于Buffer,更像是可以做指針操作的C語(yǔ)言數(shù)組。例如,可以用[index]方式直接修改某個(gè)位置的字節(jié)。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

slice方法也不是返回一個(gè)新的Buffer,而更像是返回了指向原Buffer中間的某個(gè)位置的指針,如下所示。

[ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]
    ^           ^
    |           |
   bin     bin.slice(2)
因此對(duì)slice方法返回的Buffer的修改會(huì)作用于原Buffer,例如:

復(fù)制代碼 代碼如下:

 var buffer= new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]) ;
 var sub = bin.slice(2) ;
 sub[0] = 0x65 ;
 console.log(buffer) ; //  <Buffer 68 65 65 6c 6f>

如果想要拷貝一份Buffer,得首先創(chuàng)建一個(gè)新的Buffer,并通過(guò).copy方法把原Buffer中的數(shù)據(jù)復(fù)制過(guò)去。

這個(gè)類似于申請(qǐng)一塊新的內(nèi)存,并把已有內(nèi)存中的數(shù)據(jù)復(fù)制過(guò)去。以下是一個(gè)例子。

復(fù)制代碼 代碼如下:

 var buffer= new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]) ;
 var dup = new Buffer(bin.length) ;
 buffer.copy(dup) ;
 dup[0] = 0x48 ;
 console.log(buffer) ;  // <Buffer 68 65 6c 6c 6f>
 console.log(dup) ;  // <Buffer 48 65 65 6c 6f>

總之,Buffer將JS的數(shù)據(jù)處理能力從字符串?dāng)U展到了任意二進(jìn)制數(shù)據(jù)。

以上簡(jiǎn)單讓大家了解一下什么是Buffer,下面具體說(shuō)說(shuō)如何使用和具體使用場(chǎng)景。

二,聊聊Buffer

JavaScript對(duì)字符串處理十分友好,無(wú)論是寬字節(jié)還是單字節(jié)字符串,都被認(rèn)為是一個(gè)字符串。Node中需要處理網(wǎng)絡(luò)協(xié)議、操作數(shù)據(jù)庫(kù)、處理圖片、文件上傳等,還需要處理大量二進(jìn)制數(shù)據(jù),自帶的字符串遠(yuǎn)不能滿足這些要求,因此Buffer應(yīng)運(yùn)而生。

Buffer結(jié)構(gòu)

Buffer是一個(gè)典型的Javascript和C++結(jié)合的模塊,性能相關(guān)部分用C++實(shí)現(xiàn),非性能相關(guān)部分用javascript實(shí)現(xiàn)。

Node在進(jìn)程啟動(dòng)時(shí)Buffer就已經(jīng)加裝進(jìn)入內(nèi)存,并將其放入全局對(duì)象,因此無(wú)需require

Buffer對(duì)象:類似于數(shù)組,其元素是16進(jìn)制的兩位數(shù)。

Buffer內(nèi)存分配

Buffer對(duì)象的內(nèi)存分配不是在V8的堆內(nèi)存中,在Node的C++層面實(shí)現(xiàn)內(nèi)存的申請(qǐng)。

為了高效的使用申請(qǐng)來(lái)得內(nèi)存,Node中采用slab分配機(jī)制,slab是一種動(dòng)態(tài)內(nèi)存管理機(jī)制,應(yīng)用各種*nix操作系統(tǒng)。slab有三種狀態(tài):

(1) full:完全分配狀態(tài)

(2) partial:部分分配狀態(tài)

(3) empty:沒(méi)有被分配狀態(tài)

Buffer的轉(zhuǎn)換
 
Buffer對(duì)象可以和字符串相互轉(zhuǎn)換,支持的編碼類型如下:

ASCII、UTF-8、UTF-16LE/UCS-2、Base64、Binary、Hex

字符串轉(zhuǎn)Buffer

new Buffer(str, [encoding]),默認(rèn)UTF-8
buf.write(string, [offset], [length], [encoding])

Buffer轉(zhuǎn)字符串

buf.toString([encoding], [start], [end])

Buffer不支持的編碼類型

通過(guò)Buffer.isEncoding(encoding)判斷是否支持

iconv-lite:純JavaScript實(shí)現(xiàn),更輕量,性能更好無(wú)需C++到j(luò)avascript的轉(zhuǎn)換

iconv:調(diào)用C++的libiconv庫(kù)完成

Buffer的拼接

注意 "res.on('data', function(chunk) {})",其中的參數(shù)chunk是Buffer對(duì)象,直接用+拼接會(huì)自動(dòng)轉(zhuǎn)換為字符串,對(duì)于寬字節(jié)字符可能會(huì)導(dǎo)致亂碼產(chǎn)生,

解決方法:

(1) 通過(guò)可讀流中的setEncoding()方法,該方法可以讓data事件傳遞不再是Buffer對(duì)象,而是編碼后的字符串,其內(nèi)部使用了StringEncoder模塊。

(2) 將Buffer對(duì)象暫存到數(shù)組中,最后在組裝成一個(gè)大Buffer讓后編碼轉(zhuǎn)換為字符串輸出。

Buffer在文件I/O和網(wǎng)絡(luò)I/O中廣泛應(yīng)用,其性能舉足輕重,比普通字符串性能要高出很多。

Buffer的使用除了與字符串的轉(zhuǎn)換有性能損耗外,在文件讀取時(shí)候,有一個(gè)highWaterMark設(shè)置對(duì)性能影響至關(guān)重要。

a,highWaterMark設(shè)置對(duì)Buffer內(nèi)存的分配和使用有一定影響。

b, highWaterMark設(shè)置過(guò)小,可能導(dǎo)致系統(tǒng)調(diào)用次數(shù)過(guò)多。

什么時(shí)候該用buffer,什么時(shí)候不該用  ------ 純粹的javascript支持unicode碼而對(duì)二進(jìn)制不是很支持,當(dāng)解決TCP流或者文件流的時(shí)候,處理流是有必要的,我們保存非utf-8字符串,2進(jìn)制等等其他格式的時(shí)候,我們就必須得使用 ”Buffer“ 。

三,實(shí)例引入

復(fù)制代碼 代碼如下:

 var buf = new Buffer("this is text concat test !") ,str = "this is text concat test !" ;
 console.time("buffer concat test !");
 var list = [] ;
 var len = 100000 * buf.length ;
 for(var i=0;i<100000;i++){
     list.push(buf) ;
     len += buf.length ;
 }
 var s1 = Buffer.concat(list, len).toString() ;
 console.timeEnd("buffer concat test !") ;
 console.time("string concat test !") ;
 var list = [] ;
 for (var i = 100000; i >= 0; i--) {
   list.push(str) ;
 }
 var s2 = list.join("") ;
 console.timeEnd("string concat test !") ;

以下是運(yùn)行結(jié)果:

讀取速度肯定string更快,buffer還需要toString()的操作。 所以我們?cè)诒4孀址臅r(shí)候,該用string還是要用string,就算大字符串拼接string的速度也不會(huì)比buffer慢。

那什么時(shí)候我們又需要用buffer呢?沒(méi)辦法的時(shí)候,當(dāng)我們保存非utf-8字符串,2進(jìn)制等等其他格式的時(shí)候,我們就必須得使用了。

四,總結(jié)一下

(1),JavaScript適合處理Unicode編碼數(shù)據(jù),但對(duì)二進(jìn)制數(shù)據(jù)的處理并不友好。
(2),所以處理TCP流或文件系統(tǒng)時(shí),對(duì)八位字節(jié)流的處理很有必要。
(3),Node有幾個(gè)用于處理,創(chuàng)建和消耗八位字節(jié)流的方法。
(4),原始數(shù)據(jù)存放在一個(gè)Buffer實(shí)例中,一個(gè)Buffer類似一個(gè)整數(shù)數(shù)組,但是它的內(nèi)存,分配在V8堆棧外。一個(gè)Buffer的大小是不能更改的。
(5),處理的編碼類型有:ascii,utf8,utf16le,ucs2(utf16le的別名),base64,binary,hex。
(6),Buffer為全局元素,直接new Buffer()就得到一個(gè)Buffer實(shí)例。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宣化县| 定安县| 抚顺市| 松江区| 农安县| 犍为县| 宾阳县| 许昌县| 航空| 荔波县| 新民市| 石棉县| 华池县| 永修县| 三都| 宜兴市| 伊金霍洛旗| 宜宾县| 田东县| 湖北省| 乐安县| 剑河县| 松原市| 香格里拉县| 蒲江县| 手游| 内黄县| 琼结县| 哈密市| 定襄县| 延边| 盈江县| 冷水江市| 曲麻莱县| 宁陕县| 长海县| 扎赉特旗| 随州市| 肇庆市| 祁东县| 定结县|