這篇文章將為大家詳細講解有關(guān)Buffer怎么在Node.js中使用,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供太湖網(wǎng)站建設(shè)、太湖做網(wǎng)站、太湖網(wǎng)站設(shè)計、太湖網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、太湖企業(yè)網(wǎng)站模板建站服務(wù),10余年太湖做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
Buffer:
fs.readFile('filename', function (err, buf) { //});
在使用net或http模塊來接收網(wǎng)絡(luò)數(shù)據(jù)時,data事件的參數(shù)也是一個 Buffer,這時我們還需要使用Buffer.concat()
來做數(shù)據(jù)拼接:
var bufs = []; conn.on('data', function (buf) { bufs.push(buf); }); conn.on('end', function () { // 接收數(shù)據(jù)結(jié)束后,拼接所有收到的 Buffer 對象 var buf = Buffer.concat(bufs); });
還可以利用Buffer.toString()
來做轉(zhuǎn)換base64或十六進制字符的轉(zhuǎn)換,比如:
console.log(new Buffer('hello, world!').toString('base64')); // 轉(zhuǎn)換成 base64 字符串:aGVsbG8sIHdvcmxkIQ== console.log(new Buffer('aGVsbG8sIHdvcmxkIQ==', 'base64').toString()); // 還原 base64 字符串:hello, world! console.log(new Buffer('hello, world!').toString('hex')); // 轉(zhuǎn)換成十六進制字符串:68656c6c6f2c20776f726c6421 console.log(new Buffer('68656c6c6f2c20776f726c6421', 'hex').toString()); // 還原十六進制字符串:hello, world!
一般情況下,單個 Node.js 進程是有最大內(nèi)存限制的,以下是來自官方文檔中的說明:
What is the memory limit on a node process?
Currently, by default v8 has a memory limit of 512MB on 32-bit systems, and 1.4GB on 64-bit systems. The limit can be raised by setting --max_old_space_size to a maximum of ~1024 (~1 GB) (32-bit) and ~4096 (~4GB) (64-bit), but it is recommended that you split your single process into several workers if you are hitting memory limits.
由于 Buffer 對象占用的內(nèi)存空間是不計算在 Node.js 進程內(nèi)存空間限制上的,因此,我們也常常會使用 Buffer 來存儲需要占用大量內(nèi)存的數(shù)據(jù):
// 分配一個 2G-1 字節(jié)的數(shù)據(jù) // 單次分配內(nèi)存超過此值會拋出異常 RangeError: Invalid typed array length var buf = new Buffer(1024 * 1024 * 1024 - 1);
以上便是 Buffer 的幾種常見用法。然而,閱讀 Buffer 的 API 文檔時,我們會發(fā)現(xiàn)更多的是readXXX()
和writeXXX()
開頭的 API,具體如下:
buf.readUIntLE(offset, byteLength[, noAssert])
buf.readUIntBE(offset, byteLength[, noAssert])
buf.readIntLE(offset, byteLength[, noAssert])
buf.readIntBE(offset, byteLength[, noAssert])
buf.readUInt8(offset[, noAssert])
buf.readUInt16LE(offset[, noAssert])
buf.readUInt16BE(offset[, noAssert])
buf.readUInt32LE(offset[, noAssert])
buf.readUInt32BE(offset[, noAssert])
buf.readInt8(offset[, noAssert])
buf.readInt16LE(offset[, noAssert])
buf.readInt16BE(offset[, noAssert])
buf.readInt32LE(offset[, noAssert])
buf.readInt32BE(offset[, noAssert])
buf.readFloatLE(offset[, noAssert])
buf.readFloatBE(offset[, noAssert])
buf.readDoubleLE(offset[, noAssert])
buf.readDoubleBE(offset[, noAssert])
buf.write(string[, offset][, length][, encoding])
buf.writeUIntLE(value, offset, byteLength[, noAssert])
buf.writeUIntBE(value, offset, byteLength[, noAssert])
buf.writeIntLE(value, offset, byteLength[, noAssert])
buf.writeIntBE(value, offset, byteLength[, noAssert])
buf.writeUInt8(value, offset[, noAssert])
buf.writeUInt16LE(value, offset[, noAssert])
buf.writeUInt16BE(value, offset[, noAssert])
buf.writeUInt32LE(value, offset[, noAssert])
buf.writeUInt32BE(value, offset[, noAssert])
buf.writeInt8(value, offset[, noAssert])
buf.writeInt16LE(value, offset[, noAssert])
buf.writeInt16BE(value, offset[, noAssert])
buf.writeInt32LE(value, offset[, noAssert])
buf.writeInt32BE(value, offset[, noAssert])
buf.writeFloatLE(value, offset[, noAssert])
buf.writeFloatBE(value, offset[, noAssert])
buf.writeDoubleLE(value, offset[, noAssert])
buf.writeDoubleBE(value, offset[, noAssert])
這些 API 為在 Node.js 中操作數(shù)據(jù)提供了極大的便利。假設(shè)我們要將一個整形數(shù)值存儲到文件中,比如當(dāng)前時間戳為1447656645380,如果將其當(dāng)作一個字符串存儲時,需要占用 11 字節(jié)的空間,而將其轉(zhuǎn)換為二進制存儲時僅需 6 字節(jié)空間即可:
var buf = new Buffer(6); buf.writeUIntBE(1447656645380, 0, 6); //buf.readUIntBE(0, 6); // 1447656645380
在使用 Node.js 編寫一些底層功能時,比如一個網(wǎng)絡(luò)通信模塊、某個數(shù)據(jù)庫的客戶端模塊,或者需要從文件中操作大量結(jié)構(gòu)化數(shù)據(jù)時,以上 Buffer 對象提供的 API 都是必不可少的。
接下來將演示一個使用 Buffer 對象操作結(jié)構(gòu)化數(shù)據(jù)的例子。
操作結(jié)構(gòu)化數(shù)據(jù)
假設(shè)有一個學(xué)生考試成績數(shù)據(jù)庫,每條記錄結(jié)構(gòu)如下:
學(xué)號 | 課程代碼 | 分數(shù) |
---|---|---|
XXXXXX | XXXX | XX |
其中學(xué)號是一個 6 位的數(shù)字,課程代碼是一個 4 位數(shù)字,分數(shù)最高分為 100 分。
在使用文本來存儲這些數(shù)據(jù)時,比如使用 CSV 格式存儲可能是這樣的:
100001,1001,99 100002,1001,67 100003,1001,88
其中每條記錄占用 15 字節(jié)的空間,而使用二進制存儲時其結(jié)構(gòu)將會是這樣:
學(xué)號 | 課程代碼 | 分數(shù) |
---|---|---|
3 字節(jié) | 2 字節(jié) | 1 字節(jié) |
每一條記錄僅需要 6 字節(jié)的空間即可,僅僅是使用文本存儲的 40%!下面是用來操作這些記錄的程序:
// 讀取一條記錄 // buf Buffer 對象 // offset 本條記錄在 Buffer 對象的開始位置 // data {number, lesson, score} function writeRecord (buf, offset, data) { buf.writeUIntBE(data.number, offset, 3); buf.writeUInt16BE(data.lesson, offset + 3); buf.writeInt8(data.score, offset + 5); } // 寫入一條記錄 // buf Buffer 對象 // offset 本條記錄在 Buffer 對象的開始位置 function readRecord (buf, offset) { return { number: buf.readUIntBE(offset, 3), lesson: buf.readUInt16BE(offset + 3), score: buf.readInt8(offset + 5) }; } // 寫入記錄列表 // list 記錄列表,每一條包含 {number, lesson, score} function writeList (list) { var buf = new Buffer(list.length * 6); var offset = 0; for (var i = 0; i < list.length; i++) { writeRecord(buf, offset, list[i]); offset += 6; } return buf; } // 讀取記錄列表 // buf Buffer 對象 function readList (buf) { var offset = 0; var list = []; while (offset < buf.length) { list.push(readRecord(buf, offset)); offset += 6; } return list; }
我們可以再編寫一段程序來看看效果:
var list = [ {number: 100001, lesson: 1001, score: 99}, {number: 100002, lesson: 1001, score: 88}, {number: 100003, lesson: 1001, score: 77}, {number: 100004, lesson: 1001, score: 66}, {number: 100005, lesson: 1001, score: 55}, ]; console.log(list); var buf = writeList(list); console.log(buf); // 輸出var ret = readList(buf); console.log(ret); /* 輸出 [ { number: 100001, lesson: 1001, score: 99 }, { number: 100002, lesson: 1001, score: 88 }, { number: 100003, lesson: 1001, score: 77 }, { number: 100004, lesson: 1001, score: 66 }, { number: 100005, lesson: 1001, score: 55 } ] */
lei-proto 模塊介紹
上面的例子中,當(dāng)每一條記錄的結(jié)構(gòu)有變化時,我們需要修改readRecord()
和writeRecord()
,重新計算每一個字段在 Buffer 中的偏移量,當(dāng)記錄的字段比較復(fù)雜時很容易出錯。為此我編寫了lei-proto模塊,它允許你通過簡單定義每條記錄的結(jié)構(gòu)即可生成對應(yīng)的readRecord()
和`writeRecord()
函數(shù)。
首先執(zhí)行以下命令安裝此模塊:
$ npm install lei-proto --save
使用lei-proto模塊后,前文的例子可以改為這樣:
var parsePorto = require('lei-proto'); // 生成指定記錄結(jié)構(gòu)的數(shù)據(jù)編碼/解碼器 var record = parsePorto([ ['number', 'uint', 3], ['lesson', 'uint', 2], ['score', 'uint', 1] ]); function readList (buf) { var list = []; var offset = 0; while (offset < buf.length) { list.push(record.decode(buf.slice(offset, offset + 6))); offset += 6; } return list; } function writeList (list) { return Buffer.concat(list.map(record.encodeEx)); }
運行與上文同樣的測試程序,可看到其結(jié)果是一樣的:
[ { number: 100001, lesson: 1001, score: 99 }, { number: 100002, lesson: 1001, score: 88 }, { number: 100003, lesson: 1001, score: 77 }, { number: 100004, lesson: 1001, score: 66 }, { number: 100005, lesson: 1001, score: 55 } ]
關(guān)于Buffer怎么在Node.js中使用就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。