Buffer怎么在Node.js中使用

這篇文章將為大家詳細講解有關(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) {
 // <Buffer 2f 2a 2a 0a 20 2a 20 53 75 ... >
});

在使用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ù)值存儲到文件中,比如當前時間戳為1447656645380,如果將其當作一個字符串存儲時,需要占用 11 字節(jié)的空間,而將其轉(zhuǎn)換為二進制存儲時僅需 6 字節(jié)空間即可:

var buf = new Buffer(6);

buf.writeUIntBE(1447656645380, 0, 6);
// <Buffer 01 51 0f 0f 63 04>

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ù)
XXXXXXXXXXXX

其中學(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);
// 輸出 <Buffer 01 86 a1 03 e9 63 01 86 a2 03 e9 58 01 86 a3 03 e9 4d 01 86 a4 03 e9 42 01 86 a5 03 e9 37>

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 模塊介紹

上面的例子中,當每一條記錄的結(jié)構(gòu)有變化時,我們需要修改readRecord()writeRecord() ,重新計算每一個字段在 Buffer 中的偏移量,當記錄的字段比較復(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é)果是一樣的:

<Buffer 01 86 a1 03 e9 63 01 86 a2 03 e9 58 01 86 a3 03 e9 4d 01 86 a4 03 e9 42 01 86 a5 03 e9 37>
[ { 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é)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

本文題目:Buffer怎么在Node.js中使用
網(wǎng)址分享:http://muchs.cn/article12/pdjsgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號全網(wǎng)營銷推廣、建站公司、用戶體驗、品牌網(wǎng)站制作、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)