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入门详解(多篇文章结合)
Mar 07 NodeJs
抛弃Nginx使用nodejs做反向代理服务器
Jul 17 NodeJs
Windows系统中安装nodejs图文教程
Feb 28 NodeJs
Nodejs高扩展性的模板引擎 functmpl简介
Feb 13 NodeJs
详解nodejs爬虫程序解决gbk等中文编码问题
Apr 06 NodeJs
NodeJS实现微信公众号关注后自动回复功能
May 31 NodeJs
docker中编译nodejs并使用nginx启动
Jun 23 NodeJs
nodeJS(express4.x)+vue(vue-cli)构建前后端分离实例(带跨域)
Jul 05 NodeJs
nodejs后台集成ueditor富文本编辑器的实例
Jul 11 NodeJs
nodejs使用redis作为缓存介质实现的封装缓存类示例
Feb 07 NodeJs
NodeJs生成sitemap站点地图的方法示例
Jun 11 NodeJs
如何利用nodejs实现命令行游戏
Nov 24 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
使用php+swoole对client数据实时更新(一)
2016/01/07 PHP
FormValidate 表单验证功能代码更新并提供下载
2008/08/23 Javascript
JS 无限级 Select效果实现代码(json格式)
2011/08/30 Javascript
关于javascript中的typeof和instanceof介绍
2012/12/04 Javascript
javascript通过navigator.userAgent识别各种浏览器
2013/10/25 Javascript
jquery实现效果比较好的table选中行颜色
2014/03/25 Javascript
JavaSript中变量的作用域闭包的深入理解
2014/05/12 Javascript
JavaScript给url网址进行encode编码的方法
2015/03/18 Javascript
javascript中加var和不加var的区别 你真的懂吗
2016/01/06 Javascript
Vue自定义事件(详解)
2017/08/19 Javascript
react实现一个优雅的图片占位模块组件详解
2017/10/30 Javascript
vue购物车插件编写代码
2017/11/27 Javascript
Node.js调用fs.renameSync报错(Error: EXDEV, cross-device link not permitted)
2017/12/27 Javascript
微信小程序常用简易小函数总结
2019/02/01 Javascript
eslint 的三大通用规则详解
2019/05/16 Javascript
javascript定时器的简单应用示例【控制方块移动】
2019/06/17 Javascript
编写一个javascript元循环求值器的方法
2020/04/14 Javascript
解决vue项目中某一页面不想引用公共组件app.vue的问题
2020/08/14 Javascript
python连接远程ftp服务器并列出目录下文件的方法
2015/04/01 Python
Python新手在作用域方面经常容易碰到的问题
2015/04/03 Python
分享Python字符串关键点
2015/12/13 Python
Python的Twisted框架中使用Deferred对象来管理回调函数
2016/05/25 Python
Python中的Django基本命令实例详解
2018/07/15 Python
使用50行Python代码从零开始实现一个AI平衡小游戏
2018/11/21 Python
python opencv鼠标事件实现画框圈定目标获取坐标信息
2020/04/18 Python
Python字典添加,删除,查询等相关操作方法详解
2020/02/07 Python
python subprocess pipe 实时输出日志的操作
2020/12/05 Python
h5调用摄像头的实现方法
2016/06/01 HTML / CSS
英国知名的护肤彩妆与时尚配饰大型综合零售电商:Unineed
2016/11/21 全球购物
高中考试作弊检讨书
2014/01/14 职场文书
面临毕业的毕业生自荐书范文
2014/02/05 职场文书
个人函授自我鉴定
2014/03/25 职场文书
《英英学古诗》教学反思
2014/04/11 职场文书
干部作风建设工作总结
2014/10/29 职场文书
写给导师的自荐信
2015/03/06 职场文书
Python还能这么玩之用Python修改了班花的开机密码
2021/06/04 Python