NodeJS模块Buffer原理及使用方法解析


Posted in NodeJs onNovember 11, 2020

Buffer 作为 nodejs 中重要的概念和功能,为开发者提供了操作二进制的能力。本文记录了几个问题,来加深对 Buffer 的理解和使用:

  • 认识缓冲器
  • 如何申请堆外内存
  • 如何计算字节长度
  • 如何计算字节长度
  • 如何转换字符编码
  • 理解共享内存与拷贝内存

认识 Buffer(缓冲器)

Buffer 是 nodejs 核心 API,它提供我们处理二进制数据流的功能。Buffer 的使用和 ES2017 的 Uint8Array 非常相似,但由于 node 的特性,专门提供了更深入的 api。

Uint8Array 的字面意思就是:8 位无符号整型数组。一个字节是 8bit,而字节的表示也是由两个 16 进制(4bit)的数字组成的。

const buf = Buffer.alloc(1);
console.log(buf); // output: <Buffer 00>

如何申请堆外内存

Buffer 可以跳出 nodejs 对堆内内存大小的限制。nodejs12 提供了 4 种 api 来申请堆外内存:

  • Buffer.from()
  • Buffer.alloc(size[, fill[, encoding]])
  • Buffer.allocUnsafe(size)
  • Buffer.allocUnsafeSlow(size)

Buffer.alloc vs Buffer.allocUnsafe

在申请内存时,可能这片内存之前存储过其他数据。如果不清除原数据,那么会有数据泄漏的安全风险;如果清除原数据,速度上会慢一些。具体用哪种方式,根据实际情况定。

  • Buffer.alloc:申请指定大小的内存,并且清除原数据,默认填充 0
  • Buffer.allocUnsafe:申请指定大小内存,但不清除原数据,速度更快

根据提供的 api,可以手动实现一个alloc:

function pollifyAlloc(size, fill = 0, encoding = "utf8") {
  const buf = Buffer.allocUnsafe(size);
  buf.fill(fill, 0, size, encoding);
  return buf;
}

Buffer.allocUnsafe vs Buffer.allocUnsafeSlow

从命名上可以直接看出效果,Buffer.allocUnsafeSlow更慢。因为当使用 Buffer.allocUnsafe 创建新的 Buffer 实例时,如果要分配的内存小于 4KB,则会从一个预分配的 Buffer 切割出来。 这可以避免垃圾回收机制因创建太多独立的 Buffer 而过度使用。

这种方式通过消除跟踪和清理的需要来改进性能和内存使用。

如何计算字节长度

利用 Buffer,可以获得数据的真实所占字节。例如一个汉字,它的字符长度是 1。但由于是 utf8 编码的汉字,所以占用 3 个字节。

直接利用Buffer.byteLength()可以获得字符串指定编码的字节长度:

const str = "本文原文地址: xxoo521.com";

console.log(Buffer.byteLength(str, "utf8")); // output: 31
console.log(str.length); // output: 19

也可以直接访问 Buffer 实例的 length 属性(不推荐):

console.log(Buffer.from(str, "utf8").length); // output: 31

如何转换字符编码

Nodejs 当前支持的编码格式有:ascii、utf8、utf16le、ucs2、base64、latin1、binary、hex。其他编码需要借助三方库来完成。

下面,是用Buffer.from()和buf.toString()来封装的 nodejs 平台的编码转换函数:

function trans(str, from = "utf8", to = "utf8") {
  const buf = Buffer.from(str, from);
  return buf.toString(to);
}

// output: 5Y6f5paH5Zyw5Z2AOiB4eG9vNTIxLmNvbQ==
console.log(trans("原文地址: xxoo521.com", "utf8", "base64"));

共享内存与拷贝内存

在生成 Buffer 实例,操作二进制数据的时候,千万要注意接口是基于共享内存,还是基于拷贝底层内存。

例如对于生成 Buffer 实例的from(),不同类型的参数,nodejs 底层的行为是不同的。

为了更形象地解释,请看下面两段代码。

代码 1:

const buf1 = Buffer.from("buffer");
const buf2 = Buffer.from(buf1); // 拷贝参数中buffer的数据到新的实例
buf1[0]++;

console.log(buf1.toString()); // output: cuffer
console.log(buf2.toString()); // output: buffer

代码 2:

const arr = new Uint8Array(1);
arr[0] = 97;

const buf1 = Buffer.from(arr.buffer);
console.log(buf1.toString()); // output: a

arr[0] = 98;
console.log(buf1.toString()); // output: b

在第二段代码中,传入Buffer.from的参数类型是arrayBuffer。因此Buffer.from仅仅是创建视图,而不是拷贝底层内存。buf1 和 arr 的内存是共享的。

在操作 Buffer 的过程中,需要特别注意共享和拷贝的区别,发生错误比较难排查。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
nodejs npm包管理的配置方法及常用命令介绍
Jun 05 NodeJs
nodejs分页类代码分享
Jun 17 NodeJs
nodejs的10个性能优化技巧
Jul 15 NodeJs
Nodejs实现的一个简单udp广播服务器、客户端
Sep 25 NodeJs
详谈nodejs异步编程
Dec 04 NodeJs
NodeJS与HTML5相结合实现拖拽多个文件上传到服务器的实现方法
Jul 26 NodeJs
在windows上用nodejs搭建静态文件服务器的简单方法
Aug 11 NodeJs
NodeJS使用formidable实现文件上传
Oct 27 NodeJs
nodejs中模块定义实例详解
Mar 18 NodeJs
nodejs+express搭建多人聊天室步骤
Feb 12 NodeJs
基于nodejs的雪碧图制作工具的示例代码
Nov 05 NodeJs
nodejs一个简单的文件服务器的创建方法
Sep 13 NodeJs
nodejs中内置模块fs,path常见的用法说明
Nov 07 #NodeJs
Nodejs + sequelize 实现增删改查操作
Nov 07 #NodeJs
nodejs+koa2 实现模仿springMVC框架
Oct 21 #NodeJs
nodejs使用Sequelize框架操作数据库的实现
Oct 21 #NodeJs
用Nodejs实现在终端中炒股的实现
Oct 18 #NodeJs
Nodejs在局域网配置https访问的实现方法
Oct 17 #NodeJs
NodeJS开发人员常见五个错误理解
Oct 14 #NodeJs
You might like
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
2009/03/13 PHP
php中批量替换文件名的实现代码
2011/07/20 PHP
ThinkPHP数据操作方法总结
2015/09/28 PHP
thinkPHP5.0框架应用请求生命周期分析
2017/03/25 PHP
javascript 支持链式调用的异步调用框架Async.Operation
2009/08/04 Javascript
用JQuery模仿淘宝的图片放大镜显示效果
2011/09/15 Javascript
Ext.get() 和 Ext.query()组合使用实现最灵活的取元素方式
2011/09/26 Javascript
jquery Tab效果和动态加载的简单实例
2013/12/11 Javascript
JS中的form.submit()不能提交表单的错误原因
2014/10/08 Javascript
JavaScript中的闭包介绍
2015/03/15 Javascript
纯Javascript实现ping功能的方法
2015/03/20 Javascript
7个去伪存真的JavaScript面试题
2016/01/07 Javascript
Bootstrap按钮组件详解
2016/04/26 Javascript
解析jQueryEasyUI的使用
2016/11/22 Javascript
jQuery实现两个select控件的互移操作
2016/12/22 Javascript
Angular 4依赖注入学习教程之FactoryProvider配置依赖对象(五)
2017/06/04 Javascript
JS实现经典的中国地区三级联动下拉菜单功能实例【测试可用】
2017/06/06 Javascript
微信小程序之滚动视图容器的实现方法
2017/09/26 Javascript
Node.js对MongoDB进行增删改查操作的实例代码
2019/04/18 Javascript
关于vue-cli 3配置打包优化要点(推荐)
2019/04/22 Javascript
微信小程序class封装http代码实例
2019/08/24 Javascript
[03:00]2018完美盛典_最佳英雄奖
2018/12/17 DOTA
二种python发送邮件实例讲解(python发邮件附件可以使用email模块实现)
2013/12/03 Python
python 使用get_argument获取url query参数
2017/04/28 Python
Sanic框架基于类的视图用法示例
2018/07/18 Python
基于Python的Post请求数据爬取的方法详解
2019/06/14 Python
在python shell中运行python文件的实现
2019/12/21 Python
40行Python代码实现天气预报和每日鸡汤推送功能
2020/02/27 Python
python 监控服务器是否有人远程登录(详细思路+代码)
2020/12/18 Python
python在协程中增加任务实例操作
2021/02/28 Python
详解CSS3的perspective属性设置3D变换距离的方法
2016/05/23 HTML / CSS
印尼美容产品购物网站:PerfectBeauty.id
2017/12/01 全球购物
美国在线鞋类零售商:LifeStride
2019/06/09 全球购物
Fnac西班牙官网:法国文化和电子产品零售商
2021/03/14 全球购物
个人廉洁自律承诺书
2014/03/27 职场文书
详解如何在Canvas中添加事件的方法
2021/04/17 Javascript