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 实现模拟form表单上传文件
Jul 14 NodeJs
轻松创建nodejs服务器(6):作出响应
Dec 18 NodeJs
Nodejs学习笔记之Global Objects全局对象
Jan 13 NodeJs
NodeJS实现阿里大鱼短信通知发送
Jan 17 NodeJs
Nodejs中 npm常用命令详解
Jul 04 NodeJs
nodejs开发——express路由与中间件
Mar 24 NodeJs
nodejs入门教程三:调用内部和外部方法示例
Apr 24 NodeJs
NodeJs的fs读写删除移动监听
Apr 28 NodeJs
NodeJS实现微信公众号关注后自动回复功能
May 31 NodeJs
详解nodejs实现本地上传图片并预览功能(express4.0+)
Jun 28 NodeJs
NodeJs 模仿SIP话机注册的方法
Jun 21 NodeJs
nodejs文件夹深层复制功能
Sep 03 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函数)
2006/10/09 PHP
PHP下对字符串的递增运算代码
2010/08/21 PHP
ci检测是ajax还是页面post提交数据的方法
2014/11/10 PHP
PHP在同一域名下两个不同的项目做独立登录机制详解
2017/09/22 PHP
Alliance vs Liquid BO3 第一场2.13
2021/03/10 DOTA
JavaScript 定义function的三种方式小结
2009/10/16 Javascript
Jquery AutoComplete自动完成 的使用方法实例
2010/03/19 Javascript
javascript forEach通用循环遍历方法
2010/10/11 Javascript
了解一点js的Eval函数
2012/07/26 Javascript
JavaScript使用DeviceOne开发实战(一) 配置和起步
2015/12/01 Javascript
AngularJS过滤器详解及示例代码
2016/08/16 Javascript
微信小程序实战之仿android fragment可滑动底部导航栏(4)
2020/04/16 Javascript
Angular2+国际化方案(ngx-translate)的示例代码
2017/08/23 Javascript
vue watch普通监听和深度监听实例详解(数组和对象)
2018/08/16 Javascript
nodejs实现用户登录路由功能
2019/05/22 NodeJs
Node.js fs模块(文件模块)创建、删除目录(文件)读取写入文件流的方法
2019/09/03 Javascript
解决element-ui里的下拉多选框 el-select 时,默认值不可删除问题
2020/08/14 Javascript
基于python yield机制的异步操作同步化编程模型
2016/03/18 Python
python3将视频流保存为本地视频文件
2018/06/20 Python
解决Shell执行python文件,传参空格引起的问题
2018/10/30 Python
Java文件与类动手动脑实例详解
2019/11/10 Python
Scrapy框架实现的登录网站操作示例
2020/02/06 Python
Python语法垃圾回收机制原理解析
2020/03/25 Python
python3 中时间戳、时间、日期的转换和加减操作
2020/07/14 Python
CSS3之transition实现下划线的示例代码
2018/05/30 HTML / CSS
html5 localStorage本地存储_动力节点Java学院整理
2017/07/06 HTML / CSS
菲律宾旅游网站:Expedia菲律宾
2017/10/11 全球购物
Myprotein加拿大官网:欧洲第一的运动营养品牌
2018/01/06 全球购物
英国最大的经认证的有机超市:Planet Organic
2018/02/02 全球购物
医学专业毕业生推荐信
2013/11/14 职场文书
社区活动邀请函范文
2014/01/29 职场文书
市场营销方案范文
2014/03/11 职场文书
新闻专业毕业生求职信
2014/08/08 职场文书
高一军训决心书
2015/02/05 职场文书
CSS 新特性 contain控制页面的重绘与重排问题
2021/04/30 HTML / CSS
Python基础之hashlib模块详解
2021/05/06 Python