前言

在大多数介绍 Buffer 的文章中,主要是围绕数据拼接和内存分配这两方面的。比如我们使用fs模块来读取文件内容的时候,返回的就是一个 Buffer:
fs.readFile('filename', function (err, buf) {
// <Buffer 2f 2a 2a 0a 20 2a 20 53 75 ... >
});
在使用net或http模块来接收网络数据时,data事件的参数也是一个 Buffer,这时我们还需要使用Buffer.concat()来做数据拼接:
var bufs = [];
conn.on('data', function (buf) {
bufs.push(buf);
});
conn.on('end', function () {
// 接收数据结束后,拼接所有收到的 Buffer 对象
var buf = Buffer.concat(bufs);
});
还可以利用Buffer.toString()来做转换base64或十六进制字符的转换,比如:
console.log(new Buffer('hello, world!').toString('base64'));
// 转换成 base64 字符串:aGVsbG8sIHdvcmxkIQ==
console.log(new Buffer('aGVsbG8sIHdvcmxkIQ==', 'base64').toString());
// 还原 base64 字符串:hello, world!
console.log(new Buffer('hello, world!').toString('hex'));
// 转换成十六进制字符串:68656c6c6f2c20776f726c6421
console.log(new Buffer('68656c6c6f2c20776f726c6421', 'hex').toString());
// 还原十六进制字符串:hello, world!
一般情况下,单个 Node.js 进程是有最大内存限制的,以下是来自官方文档中的说明:
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 对象占用的内存空间是不计算在 Node.js 进程内存空间限制上的,因此,我们也常常会使用 Buffer 来存储需要占用大量内存的数据:
// 分配一个 2G-1 字节的数据 // 单次分配内存超过此值会抛出异常 RangeError: Invalid typed array length var buf = new Buffer(1024 * 1024 * 1024 - 1);
以上便是 Buffer 的几种常见用法。然而,阅读 Buffer 的 API 文档时,我们会发现更多的是readXXX()和writeXXX()开头的 API,具体如下:
这些 API 为在 Node.js 中操作数据提供了极大的便利。假设我们要将一个整形数值存储到文件中,比如当前时间戳为1447656645380,如果将其当作一个字符串存储时,需要占用 11 字节的空间,而将其转换为二进制存储时仅需 6 字节空间即可:
var buf = new Buffer(6); buf.writeUIntBE(1447656645380, 0, 6); // <Buffer 01 51 0f 0f 63 04> buf.readUIntBE(0, 6); // 1447656645380
在使用 Node.js 编写一些底层功能时,比如一个网络通信模块、某个数据库的客户端模块,或者需要从文件中操作大量结构化数据时,以上 Buffer 对象提供的 API 都是必不可少的。
接下来将演示一个使用 Buffer 对象操作结构化数据的例子。
操作结构化数据
假设有一个学生考试成绩数据库,每条记录结构如下:
| 学号 | 课程代码 | 分数 |
|---|---|---|
| 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('lei-proto');
// 生成指定记录结构的数据编码/解码器
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));
}
运行与上文同样的测试程序,可看到其结果是一样的:
<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 } ]
关于lei-proto模块的详细使用方法可访问该模块的主页浏览:https://github.com/leizongmin/node-lei-proto
对此感兴趣的读者也可研究一下其实现原理。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# nodejs
# buffer
# 拼接
# string
# node.JS二进制操作模块buffer对象使用方法详解
# node.js中Buffer缓冲器的原理与使用方法分析
# Node.js Buffer模块功能及常用方法实例分析
# 详解如何在Node.js的httpServer中接收前端发送的arraybuffer数据
# 浅谈Node.js:Buffer模块
# Node.js 缓冲区(Buffer)模块的方法及实例分析
# 是一个
# 每条
# 是这样
# 结构化
# 将其
# 来做
# 转换成
# 的是
# 都是
# 文档
# 还可以
# 是有
# 将会
# 很容易
# 也可
# 感兴趣
# 我们可以
# 来看看
# 仅仅是
# 写了
相关文章:
制作农业网站的软件,比较好的农业网站推荐一下?
公司网站建设制作费用,想建设一个属于自己的企业网站,该如何去做?
,巨量百应是干嘛的?
如何在万网开始建站?分步指南解析
电脑免费海报制作网站推荐,招聘海报哪个网站多?
网站制作公司,橙子建站是合法的吗?
桂林网站制作公司有哪些,桂林马拉松怎么报名?
如何在阿里云购买域名并搭建网站?
如何在万网主机上快速搭建网站?
网站制作网站,深圳做网站哪家比较好?
如何高效完成自助建站业务培训?
邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?
如何快速搭建支持数据库操作的智能建站平台?
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
如何在IIS中新建站点并解决端口绑定冲突?
台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?
如何基于云服务器快速搭建网站及云盘系统?
深圳网站制作培训,深圳哪些招聘网站比较好?
微信小程序 五星评分(包括半颗星评分)实例代码
Android滚轮选择时间控件使用详解
如何访问已购建站主机并解决登录问题?
香港服务器建站指南:免备案优势与SEO优化技巧全解析
建站之星收费标准详解:套餐费用及年费价格表一览
湖州网站制作公司有哪些,浙江中蓝新能源公司官网?
已有域名和空间,如何快速搭建网站?
高防服务器:AI智能防御DDoS攻击与数据安全保障
建站之星会员如何解锁更多建站功能?
南京网站制作费用,南京远驱官方网站?
,怎么用自己头像做动态表情包?
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
如何通过FTP服务器快速搭建网站?
如何通过服务器快速搭建网站?完整步骤解析
建站之星免费版是否永久可用?
如何在景安云服务器上绑定域名并配置虚拟主机?
深入理解Android中的xmlns:tools属性
高端企业智能建站程序:SEO优化与响应式模板定制开发
武汉网站如何制作,黄黄高铁武穴北站途经哪些村庄?
专业商城网站制作公司有哪些,pi商城官网是哪个?
如何在宝塔面板创建新站点?
怀化网站制作公司,怀化新生儿上户网上办理流程?
无锡营销型网站制作公司,无锡网选车牌流程?
如何在IIS服务器上快速部署高效网站?
网站制作模板下载什么软件,ppt模板免费下载网站?
,交易猫的商品怎么发布到网站上去?
建站VPS配置与SEO优化指南:关键词排名提升策略
c# 在ASP.NET Core中管理和取消后台任务
网站好制作吗知乎,网站开发好学吗?有什么技巧?
外汇网站制作流程,如何在工商银行网站上做外汇买卖?
建站之星2.7模板快速切换与批量管理功能操作指南
建站之星云端配置指南:模板选择与SEO优化一键生成
*请认真填写需求信息,我们会在24小时内与您取得联系。