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写的一个简单项目打包工具
May 11 NodeJs
Windows系统中安装nodejs图文教程
Feb 28 NodeJs
nodeJS代码实现计算交社保是否合适
Mar 09 NodeJs
nodejs简单实现中英文翻译
May 04 NodeJs
实例详解Nodejs 保存 payload 发送过来的文件
Jan 14 NodeJs
Highcharts+NodeJS搭建数据可视化平台示例
Jan 01 NodeJs
nodeJs链接Mysql做增删改查的简单操作
Feb 04 NodeJs
浅析 NodeJs 的几种文件路径
Jun 07 NodeJs
Mac下通过brew安装指定版本的nodejs教程
May 17 NodeJs
Nodejs模块的调用操作实例分析
Dec 25 NodeJs
Nodejs中使用puppeteer控制浏览器中视频播放功能
Aug 26 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
php中利用str_pad函数生成数字递增形式的产品编号
2013/09/30 PHP
destoon官方标签大全
2014/06/20 PHP
PHP实现超简单的SSL加密解密、验证及签名的方法示例
2017/08/28 PHP
php获取ajax的headers方法与内容实例
2017/12/27 PHP
PHP crypt()函数的用法讲解
2019/02/15 PHP
JS幻灯片可循环播放可平滑旋转带滚动导航(自写)
2013/08/05 Javascript
网页中可关闭的漂浮窗口实现可自行调节
2013/08/20 Javascript
node.js中的socket.io入门实例
2014/04/26 Javascript
如何让你的Lightbox支持滚轮缩放及Base64图片
2014/12/04 Javascript
简单谈谈javascript代码复用模式
2015/01/28 Javascript
jQuery内部原理和实现方式浅析
2015/02/03 Javascript
JavaScript使用二分查找算法在数组中查找数据的方法
2015/04/07 Javascript
js console.log打印对像与数组用法详解
2016/01/21 Javascript
JavaScript创建对象_动力节点Java学院整理
2017/06/27 Javascript
JavaScript实现鼠标滚轮控制页面图片切换功能示例
2017/10/14 Javascript
vue实现验证码输入框组件
2017/12/14 Javascript
简单谈谈CommonsChunkPlugin抽取公共模块
2017/12/31 Javascript
vue实现自定义日期组件功能的实例代码
2018/11/06 Javascript
Web安全之XSS攻击与防御小结
2018/12/13 Javascript
微信小程序如何访问公众号文章
2019/07/08 Javascript
JavaScript前端页面搜索功能案例【基于jQuery】
2019/07/10 jQuery
JS回调函数原理与用法详解【附PHP回调函数】
2019/07/20 Javascript
[03:20]2015国际邀请赛全明星表演赛
2015/08/08 DOTA
分享15个最受欢迎的Python开源框架
2014/07/13 Python
python的迭代器与生成器实例详解
2014/07/16 Python
python+django加载静态网页模板解析
2017/12/12 Python
对python判断ip是否可达的实例详解
2019/01/31 Python
django使用django-apscheduler 实现定时任务的例子
2019/07/20 Python
python3 深浅copy对比详解
2019/08/12 Python
pytorch实现mnist数据集的图像可视化及保存
2020/01/14 Python
Python进行统计建模
2020/08/10 Python
罗兰·穆雷官网:Roland Mouret
2018/09/28 全球购物
GC是什么?为什么要有GC?
2013/12/08 面试题
关于flex 上下文中自动 margin的问题(完整例子)
2021/05/20 HTML / CSS
OpenCV-Python实现人脸美白算法的实例
2021/06/11 Python
python之json文件转xml文件案例讲解
2021/08/07 Python