Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erklärung einiger übersehener Verwendung von Buffer in Node.js

Detaillierte Erklärung einiger übersehener Verwendung von Buffer in Node.js

黄舟
黄舟Original
2017-03-28 14:23:531474Durchsuche

Online-Artikel über die Verwendung von Buffer in Node.js Es gibt viele, aber ich habe das Gefühl, dass sie immer noch nicht detailliert genug sind, daher stellt dieser Artikel hauptsächlich einige Verwendungen von Buffer in Node.js vor, die Sie möglicherweise nicht kennen. Freunde, die es benötigen, können darauf verweisen . Werfen wir gemeinsam einen Blick darauf.

Vorwort

In den meisten Artikeln geht es hauptsächlich um die beiden Aspekte des Datenspleißens Speicherzuweisung. Bei Verwendung des fs-Moduls zum Lesen des Inhalts der Datei wird ein Puffer zurückgegeben:

fs.readFile('filename', function (err, buf) {
 // <Buffer 2f 2a 2a 0a 20 2a 20 53 75 ... >
});

Bei Verwendung des Netz- oder http-Moduls zum Empfangen von Netzwerkdaten werden die Daten zurückgegeben Ereignis ist auch ein Puffer. Zu diesem Zeitpunkt müssen wir auch für das Datenspleißen verwenden: Buffer.concat()

var bufs = [];
conn.on(&#39;data&#39;, function (buf) {
 bufs.push(buf);
});
conn.on(&#39;end&#39;, function () {
 // 接收数据结束后,拼接所有收到的 Buffer 对象
 var buf = Buffer.concat(bufs);
});
Sie können auch

verwenden, um base64 zu konvertieren oder hexadezimale Zeichen. Zum Beispiel: Buffer.toString()

console.log(new Buffer(&#39;hello, world!&#39;).toString(&#39;base64&#39;));
// 转换成 base64 字符串:aGVsbG8sIHdvcmxkIQ==

console.log(new Buffer(&#39;aGVsbG8sIHdvcmxkIQ==&#39;, &#39;base64&#39;).toString());
// 还原 base64 字符串:hello, world!

console.log(new Buffer(&#39;hello, world!&#39;).toString(&#39;hex&#39;));
// 转换成十六进制字符串:68656c6c6f2c20776f726c6421

console.log(new Buffer(&#39;68656c6c6f2c20776f726c6421&#39;, &#39;hex&#39;).toString());
// 还原十六进制字符串:hello, world!
Im Allgemeinen hat ein einzelner Node.js-Prozess ein maximales Speicherlimit. Das Folgende ist eine Erklärung aus der offiziellen Dokumentation:

Was ist der Speicher? Limit für einen Knotenprozess?

Derzeit hat v8 standardmäßig ein Speicherlimit von 512 MB auf 32-Bit-Systemen und 1,4 GB auf 64-Bit-Systemen. Das Limit kann durch Setzen von --max_old_space_size auf a erhöht werden maximal ~1024 (~1 GB) (32-Bit) und ~4096 (~4GB) (64-Bit), es wird jedoch empfohlen, Ihren einzelnen Prozess in mehrere Worker aufzuteilen, wenn Sie an Speichergrenzen stoßen.

Aufgrund des vom Buffer-Objekt belegten Speicherplatzes wird das Speicherplatzlimit des Node.js-Prozesses nicht berücksichtigt. Daher verwenden wir Buffer häufig zum Speichern von Daten, die viel Speicher erfordern:

// 分配一个 2G-1 字节的数据
// 单次分配内存超过此值会抛出异常 RangeError: Invalid typed array length
var buf = new Buffer(1024 * 1024 * 1024 - 1);
Das Obige ist Buffer. Wenn wir jedoch die API-Dokumentation von Buffer lesen, werden wir weitere APIs finden, die mit

und readXXX() beginnen, wie folgt: writeXXX()

  • buf. 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][,kodierung])

  • 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])


Diese APIs bieten großen Komfort für den Betrieb von Daten in Node.js. Angenommen, wir möchten einen ganzzahligen Wert in einer Datei speichern. Der aktuelle

-Zeitstempel ist beispielsweise 1447656645380. Wenn wir ihn als Zeichenfolge speichern, nimmt er 11 Byte Platz ein und konvertiert ihn in eine Binärdatei. Für die Speicherung werden nur 6 Byte Speicherplatz benötigt:

var buf = new Buffer(6);

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

buf.readUIntBE(0, 6);
// 1447656645380
Wenn Sie Node.js zum Schreiben einiger Low-Level-Funktionen verwenden, z. B. eines Netzwerkkommunikationsmoduls, eines Clientmoduls einer Datenbank, oder Sie müssen dies tun Lesen Sie es aus einer Datei. Bei der Verarbeitung großer Mengen strukturierter Daten sind die von den oben genannten Buffer-Objekten bereitgestellten APIs unerlässlich.

Im Folgenden wird ein Beispiel für die Verwendung des Buffer-Objekts zur Bearbeitung strukturierter Daten gezeigt.

操作结构化数据

假设有一个学生考试成绩数据库,每条记录结构如下:

学号 课程代码 分数
XXXXXX XXXX XX

其中学号是一个 6 位的数字,课程代码是一个 4 位数字,分数最高分为 100 分。

在使用文本来存储这些数据时,比如使用 CSV 格式存储可能是这样的:

100001,1001,99
100002,1001,67
100003,1001,88

其中每条记录占用 15 字节的空间,而使用二进制存储时其结构将会是这样:

学号 课程代码 分数
3 字节 2 字节 1 字节

每一条记录仅需要 6 字节的空间即可,仅仅是使用文本存储的 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 模块介绍

上面的例子中,当每一条记录的结构有变化时,我们需要修改readRecord()writeRecord() ,重新计算每一个字段在 Buffer 中的偏移量,当记录的字段比较复杂时很容易出错。为此我编写了lei-proto模块,它允许你通过简单定义每条记录的结构即可生成对应的readRecord()`writeRecord()函数。

首先执行以下命令安装此模块:

$ npm install lei-proto --save

使用lei-proto模块后,前文的例子可以改为这样:

var parsePorto = require(&#39;lei-proto&#39;);

// 生成指定记录结构的数据编码/解码器
var record = parsePorto([
 [&#39;number&#39;, &#39;uint&#39;, 3],
 [&#39;lesson&#39;, &#39;uint&#39;, 2],
 [&#39;score&#39;, &#39;uint&#39;, 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));
}

运行与上文同样的测试程序,可看到其结果是一样的:

<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 } ]

总结

Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung einiger übersehener Verwendung von Buffer in Node.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn