Node.js開發入門—Buffer用法詳解

來源:互聯網
上載者:User

Node.js開發入門—Buffer用法詳解

Node.js中有一個Buffer類,必須要介紹一下,因為我們在使用Node.js做服務端開發時,http、tcp、udp、檔案io等等類型的操作,都會用到Buffer,離開它基本沒辦法玩兒下去。

Buffer是什麼

JavaScript裡的String對象,儲存的是字串,而且是Unicode編碼的。

Buffer代表一個緩衝區,儲存位元據,是位元組流。我們在網路傳輸時,就傳輸的這種位元組流。寫檔案時,也是寫的位元組流。

編碼格式

字串是有編碼格式的,比如UTF-8。而Buffer是沒有編碼格式的。兩者可以相互轉換。轉換時必須指定編碼格式。

我們之前已經用過的http模組(參看Node.js開發入門——HTTP檔案伺服器Node.js開發入門——HelloWorld再分析),http.createServer方法需要的回呼函數的原型是:

function (req, res)

這個回調的第一個參數,req,類型是http.IncomingMessage,而http.IncomingMessage是一個唯讀流,實現了Readable介面,stream.Readable讀到的資料(監聽data事件可以處理),就是Buffer對象,是位元組流。而我們在程式中使用時,經常是要轉換為String。反過來,res(類型http.ServerResponse,可寫的流,實現了Writable介面)有個方法setDefaultEncoding,用來設定流的編碼格式,在write資料時,會使用指定的編碼格式來編碼資料,然後發送給用戶端。

就是說,網路傳輸的是Buffer,程式需要處理String,Buffer和String之間可以轉換。Buffer有toString方法,可以按指定的編碼格式將位元組流轉換為String。

還有,檔案系統模組(參看Node.js開發入門——使用http訪問外部世界或Node.js開發入門——HTTP檔案伺服器),fs.createWriteStream和fs.createReadStream兩個方法都有一個選擇性參數options,可以指定defaultEncoding,這裡指定的編碼格式,也是用於在Buffer和String之間轉換的。

目前我們在Node.js裡,Buffer在轉換為字串時,toString方法的第一個參數就是編碼類別型,支援常見的編碼格式:

utf8,多位元組編碼的Unicode字元,大多數文檔和網頁採用這種編碼格式 ascii,8bit編碼,一個字元佔1個位元組 utf16le,小端編碼的unicode字元 utf16be,大端編碼的unicode ucs2,unicode編碼,每個字元佔兩個位元組 base64,Base-64字串編碼 hex,每個位元組編碼為兩個十六進位字元

假如你不確認某個編碼格式是否正確,可以使用Buffer.isEncoding(encoding)方法來測試。

在使用Buffer的toString方法時,如果你不指定編碼格式,則預設使用utf8來轉換。toString原型:

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

第一個參數是編碼格式,第二個是開始位置(0到buf.length-1),第三個是結束位置(不包含這個索引位置的資料)。

建立一個Buffer執行個體

使用new操作符,有四種方法建立一個Buffer執行個體:

new Buffer(size),建立一個指buffer定大小的buffer new Buffer(array),根據一個位元組數組來建立一個buffer new Buffer(str[,encoding]),根據一個字串和編碼格式建立buffer,不指定編碼時預設使用utf8 new Buffer(buffer),根據buffer執行個體建立一個新的buffer

比如下面的代碼可以建立Buffer的執行個體:

var buf1 = new Buffer(256);var buf2 = new Buffer(Hello Buffer);var buf3 = new Buffer([0x65,0x66,0x67]);var buf4 = new Buffer(buf2);

有一點需要說明,使用new Buffer(size)分配的緩衝區,是未初始化的哦。那塊記憶體裡,可能是髒的,什麼玩意兒都有。試試下面的代碼:

var buf1 = new Buffer(256);buf1.write('abc');console.log(buf1's content: , buf1.toString());

上面的代碼企圖使用toString轉換Buffer,可是你會看到控制台輸出了很多亂碼……修改一下,使用buf.fill()方法填充一下就好了:

var buf1 = new Buffer(256);buf1.fill(0);buf1.write('abc');console.log(buf1's content: , buf1.toString());

字串是“”結尾的,調用了buf1.fill(0)之後,就一切安好。

往緩衝區寫資料

前面我們已經使用了buf.write方法來向緩衝區裡寫入資料了。write的原型如下:

buf.write(string[, offset][, length][, encoding])

buf.write用來向緩衝區中寫入一個字串,返回實際寫入的位元組數。參數含義如下:

string,待寫入的字串對象 offset,緩衝區位移量,指定的話就從這個位置開始寫入,不指定就預設為0 length,要寫入的位元組數 encoding,代謝如字串的編碼格式,預設為utf8

Buffer還有很多其他的方法,讓你操作緩衝區。比如writeUInt8、writeUInt16LE、writeUInt16BE、writeUInt31LE、writeUInt32BE、writeInt8、writeInt16LE、writeInt32LE等等。

LE - little endian,小端位元組序。
BE - big endian,大端位元組序,即網路位元組序。

需要說明的是,writeX方法,不像檔案一樣自動為你儲存當前位置哦,你不指定offset,它就總是從0位置開始寫……

其它的,看文檔吧……

從緩衝區讀資料

buf.toString其實是一種讀資料的方式。當然,還有其它的,比如buf[index]可以根據下標讀取位元組,buf.readIntXXX,buf.readUIntXXX……

buf.toJSON()可以把一個Buffer對象轉換為JSON格式。當你針對一個Buffer對象調用JSON.stringify方法時,buf.toJSON()就會被調用。比如:

var buf = new Buffer('test');var json = JSON.stringify(buf);console.log(json);// '{type:Buffer,data:[116,101,115,116]}'
緩衝區的長度

一個Buffer對象的大小,在建立時就固定下來,建立之後不可改變。嘿嘿,這可是容易引起誤解的,尤其是你覺得Buffer裡儲存的是字串時。試試下面的代碼有助於理解這一點:

var buf1 = new Buffer(256);buf1.fill(0);buf1.write('abc');console.log(buf1's length - %d, not 3, buf1.length);buf1.write('abcdef');console.log(buf1's length - %d, not 6, buf1.length);

另外當你要從確定字串在緩衝區中佔用的位元組長度時,不能使用字串的length屬性,因為String.length返回的是字元長度。而對於採用UTF8等編碼格式編碼的字串,一個字元可能佔用多個位元組。所以,String.length所代表的字串長度和位元組長度就不一致。注意,Buffer.length返回的是緩衝區的位元組長度,而且是建立時的那個長度,不會隨著緩衝內容變化而變化。

要想衡量一個字串佔用的位元組長度,可以使用Buffer.byteLength(string[,encoding])這個方法,它會測量一個字串在指定編碼格式下佔用的位元組長度。

來看一個簡單的例子:

var name = new String('who is 張三丰?');console.log('name.length = %d', name.length);console.log('byteLength = %d', Buffer.byteLength(name, 'utf8'));
緩衝區操作

Buffer還支援切片、拷貝、拼接、比較等操作。

buf.slice([start[, end]])可以根據起止位置(不包含結束位置對應的資料)對一個緩衝區進行切片,返回一個新的Buffer對象,方便我們操作緩衝區的某個地區。但值得注意的是,這個切片是對原有緩衝區的引用,而不是副本,你對切片內容的修改,實際上修改的是原始的緩衝區。這個方法返回一個代表切片的Buffer對象。

buf.copy(targetBuffer[, targetStart][, sourceStart][, sourceEnd])可以將一個緩衝區指定地區的內容拷貝到另一個緩衝的指定地區。類似C語言裡的memcpy。targetStart指定目標緩衝區的起始位移,sourceStart指定源緩衝區的起始位移,它們預設都是0;sourceEnd指定源緩衝區的結束位置,預設是源緩衝區的長度。實際複製時,會比較目標緩衝區的長度和待覆制地區的長度,哪個小按哪個來,不會越界。

Buffer有一個類方法,concat(list[,totalLength]),可以將一串緩衝區拼接成一個。第一個參數list是一個緩衝區數組,第二是待拼接的緩衝區的總長度。如果你不提供totalLength,concat會自己遍曆list中的緩衝區計算總長度,會有一點效能損失。這個方法返回拼接後的緩衝區。

看個範例程式碼,示範切片、拷貝和拼接的用法:

var buf1 = new Buffer('1234');var buf2 = new Buffer('12567');var bufList = [buf1, buf2];var buf3 = Buffer.concat(bufList);console.log('buf3 - %s', buf3.toString());var buf4 = buf3.slice(3, 8);console.log('buf4 - %s', buf4.toString());var buf5 = new Buffer(5);buf3.copy(buf5, 0, 1);console.log('buf5 - %s', buf5.toString());

buf.equals(otherBuffer)判斷當前緩衝區是否和另一個相等,相等時返回true。

buf.compare(otherBuffer)比較當前緩衝區和另一個緩衝區的大小,相等返回0,小於返回-1,大於返回1。看下面的範例程式碼:

var buf1 = new Buffer('1234');var buf2 = new Buffer('12567');var buf3 = new Buffer('1234');var buf4 = new Buffer('0123');console.log('buf1.compare(buf2) = ', buf1.compare(buf2));console.log('buf1.compare(buf3) = ', buf1.compare(buf3));console.log('buf1.compare(buf4) = ', buf1.compare(buf4));

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.