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极简入门教程(一):模块机制
Oct 25 NodeJs
Nodejs实现多人同时在线移动鼠标的小游戏分享
Dec 06 NodeJs
NodeJs——入门必看攻略
Jun 27 NodeJs
nodejs中全局变量的实例解析
Mar 07 NodeJs
用Nodejs搭建服务器访问html、css、JS等静态资源文件
Apr 28 NodeJs
Nodejs中使用captchapng模块生成图片验证码
May 18 NodeJs
nodejs实现大文件(在线视频)的读取
Oct 16 NodeJs
详解NodeJS Https HSM双向认证实现
Mar 12 NodeJs
nodejs微信开发之授权登录+获取用户信息
Mar 17 NodeJs
nodejs读取图片返回给浏览器显示
Jul 25 NodeJs
nodejs开发一个最简单的web服务器实例讲解
Jan 02 NodeJs
nodejs各种姿势断点调试的方法
Jun 18 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源码之 ext/mysql扩展部分
2009/07/17 PHP
php简单统计中文个数的方法
2016/09/30 PHP
利用PHP生成CSV文件简单示例
2016/12/21 PHP
PHP将数据导出Excel表中的实例(投机型)
2017/07/31 PHP
PHP receiveMail实现收邮件功能
2018/04/25 PHP
PHP数组去重的更快实现方式分析
2018/05/09 PHP
PHP以json或xml格式返回请求数据的方法
2018/05/31 PHP
PHP高并发和大流量解决方案整理
2019/12/24 PHP
Javascript实现简单二级下拉菜单实例
2014/06/15 Javascript
js实现touch移动触屏滑动事件
2015/04/17 Javascript
AngularJS 中的指令实践开发指南(一)
2016/03/20 Javascript
EasyUI Combobox设置默认值 获取text的方法
2016/11/28 Javascript
vue.js学习之UI组件开发教程
2017/07/03 Javascript
nodejs 图解express+supervisor+ejs的用法(推荐)
2017/09/08 NodeJs
bootstrap table列和表头对不齐的解决方法
2019/07/19 Javascript
小程序跳转H5页面的方法步骤
2020/03/06 Javascript
Vue实现可移动水平时间轴
2020/06/29 Javascript
Python列表(list)、字典(dict)、字符串(string)基本操作小结
2014/11/28 Python
python实现将英文单词表示的数字转换成阿拉伯数字的方法
2015/07/02 Python
Python用list或dict字段模式读取文件的方法
2017/01/10 Python
pyqt5简介及安装方法介绍
2018/01/31 Python
python实现requests发送/上传多个文件的示例
2018/06/04 Python
python保存字典和读取字典的实例代码
2019/07/07 Python
Python新建项目自动添加介绍和utf-8编码的方法
2020/12/26 Python
Html5写一个简单的俄罗斯方块小游戏
2019/12/03 HTML / CSS
德国柯吉澳趣味家居:Koziol
2017/08/24 全球购物
帕克纽约:PARKER NY
2018/12/09 全球购物
澳大利亚优质的家居用品和生活方式公司:Bed Bath N’ Table
2019/04/16 全球购物
波兰办公用品和学校用品在线商店:Dlabiura24.pl
2020/11/18 全球购物
如何理解委托
2012/01/06 面试题
食品流通安全承诺书
2014/05/22 职场文书
《中国梦我的梦》大学生演讲稿
2014/08/20 职场文书
新闻稿件写作技巧
2015/07/18 职场文书
北京大学中文系教授推荐的10本小说
2019/08/08 职场文书
css3 filter属性的使用简介
2021/03/31 HTML / CSS
quickjs 封装 JavaScript 沙箱详情
2021/11/02 Javascript