首先Node對字符串的支持十分的友好,無論是單字節還是多字節都被認爲是一個字符串。之所以需要Buffer對象,是因爲JavaScript本身自有的字符串對前端操作可以滿足,但是面對後臺的操作例如操作DB,處理網絡協議,文件上傳等還需要處理大量二進制數據時,JavaScript自身的字符串時無法滿足這種需求的。
1. Buffer的初識
Buffer是一個像Array的對象,主要用於操作字節,Buffer是C++與JavaScript結合的產物,對於性能方面採用C++,非性能方面採用JavaScript,之前咱們提到過Buffer是堆外內存,不是有V8分配的,因爲是常用模塊所以Node在啓動時會自動加載,並掛載到global對象上,所以在使用的時候無需require引入。
var buffer = new Buffer(length);
2. Buffer的內存管理
首先Buffer真正的內存時在C++層面上進行的申請,在JavaScript層面上使用,如果用一點內存去申請一點的話,儘管是合理的方式,但是這樣會造上內存調用上的性能消耗,所以對於Buffer而言Node採用的是動態內存管理(slab),同時Buffer區分大/小對象,以8k大小爲界限(8*1024),也就是slab的存儲單位,在內存分配上,如果是1slab不足以存儲一個對象則會創建一個新的單位,在新的單位裏進行存儲,之前未存滿的單元會被之前的小對象獨佔。
3. Buffer的轉化
· String=>Buffer
buffer.wirte(string, [offset], [length], [encoding]);
· Buffer=>String
buffer.toString([encoding], [start], [end]);
* 並不是所有的編碼類型在Buffer中都支持轉化,可以用Buffer.IsEncoding(encoding)來判斷是否支持,如果不支持可以用生態圈中的其他模塊來解決。
3. 對於亂碼的解決方案
// 拼接
var chunks = [];
var size = 0;
res.on('data', function(chunk){
chunks.push(chunk);
size += chunk.length;
});
res.on('end', function(){
var buffer = Buffer.contat(chunks, size);
var str = iconv.decode(buffer, 'utf-8');
console.info(str);
});
// 圍觀一下細膩的Buffer.contact()
Buffer.concat = function(list, length){
if(!Array.isArray(list)){
thorw new Error('error');
}
if(list.length === 0){
return new Buffer(0)
}else if(list.length === 1){
return list[0];
}
if(typeof(length !== 'number'){
length = 0;
for(var i = 0 ; i < list.length; i++){
var buf = list[i];
length += buf.length;
}
}
var buffer = new Buffer(length);
var pos = 0;
for(var i = 0; i < list.length; i++){
var buf = list[i];
buf.copy(buffer, pos);
pos += buf.length;
}
return buffer;
}