深入Node模块Buffer-学会操作二进制

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 的过程中,需要特别注意共享和拷贝的区别,发生错误比较难排查。
参考链接
Buffer 文档 MDN Uint8Array How to use Buffers in Node.js Do you want a better understanding of Buffer in Node.js? Check this out. An Introduction to Buffer in Node.js
最后
觉得不错,帮忙点个推荐呗,您的支持是对我最大的激励 欢迎我的公众号:「心谭博客」,只专注于前端 + 算法的原创分享
深入Node模块Buffer-学会操作二进制的更多相关文章
- node.js—Buffer类(二进制数据处理模块)
Buffer类概述 一个用于更好的操作二进制数据的类 我们在操作文件或者网络数据的时候,其实操作的就是二进制数据流 Node为我们提供了一个更加方便的去操作这种数据流的类 Buffer,他是一个全局的 ...
- node的buffer模块
Buffer这块很早前就想留一篇笔记.前端JS处理buffer的场景其实并不多,虽然后来基于webGL与显卡通信的需求增加了二进制数组,但毕竟相对小众. Buffer的含义是,在数据传输时用内存中的一 ...
- Node.js缓冲模块Buffer
前言 Javascript是为浏览器而设计的,能很好的处理unicode编码的字符串,但对于二进制或非unicode编码的数据就显得无能为力. Node.js继承Javascript的语言特性,同时又 ...
- Node.js之使用Buffer类处理二进制数据
Node.js之使用Buffer类处理二进制数据 Buffer类可以在处理TCP流或文件流时处理二进制数据,该类用来创建一个专门存放二进制数据的缓存区. 1. 创建Buffer对象 1.1 直接创建: ...
- node使用buffer生成图片
buffer是node里的一个模块,这个模块的出现是因为js没有阅读和操作二进制数据流而出现的 buffer是什么及作用? Buffer顾名思义叫缓冲区,用于存储速度不同步的设备或优先级不同的设备之间 ...
- 模块机制 之commonJs、node模块 、AMD、CMD
在其他高级语言中,都有模块中这个概念,比如java的类文件,PHP有include何require机制,JS一开始就没有模块这个概念,起初,js通过<script>标签引入代码的方式显得杂 ...
- Node.js Buffer(缓冲区)
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型. 但在处理像TCP流或文件流时,必须使用到二进制数据.因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门 ...
- node 之 Buffer 笔记
1. Buffer 相关 js 最初是被设计来处理 html的,因此它不善于处理二进制数据,只有数值和字符串类型.而 node 是基于 js 的,因为 node 需要实现一些譬如数据库通信.操作图像及 ...
- nodeJS-使用buffer类处理二进制数据
使用buffer类处理二进制数据 在客户端javascript脚本代码中,对于二进制数据并没有提供一个很好的支持.然后在nodejs中需要处理像TCP流或文件流时,必须要处理二进制数据.因此在node ...
随机推荐
- CodeForces 906D (欧拉降幂)
Power Tower •题意 求$w_{l}^{w_{l+1}^{w_{l+2}^{w_{l+3}^{w_{l+4}^{w_{l+5}^{...^{w_{r}}}}}}}}$ 对m取模的值 •思路 ...
- Mac 安装Maven,并设置环境变量
1 / 打开电脑,找到终端命令行工具,输入maven环境变量查询工具: mvn -v 2 / 执行上述命令后,此时没有安装的两个提示信息,一个时没有mvn命令,一个时没有安装maven.执行下面命令开 ...
- Mysql(超级详细)
Mysql(超级详细) (黑小子-余) 一.Mysql介绍 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理 ...
- rest_framework框架之认证功能的使用和源码实现流程分析
rest_framework框架之认证的使用和源码实现流程分析 一.认证功能的源码流程 创建视图函数 Note 创建视图函数后,前端发起请求,url分配路由,执行视图类,视图类中执行对应方法必须经过d ...
- javaweb项目部署到tomcat之后java文件没有编译
1.选中你的项目==>选择Project 2.将Build Automatcally前的对号去掉后再Clean一下你的项目 这样就可以了,
- VC windows 多网卡情况下 获取当前网卡ip地址
参考 代码如下 记录下以后用得到或者能帮到有需要的朋友 #include <iostream> #include <WinSock2.h> #include <Iphlp ...
- spring cloud 微服务之 -- 配置文件拆分之道
0-前言 在spring cloud微服务架构中,基本上每个拆分的微服务都会部署多个运行实例,这些运行实例,配置基本都是一样的,不同的是少数配置,比如端口,而这些不同的配置又是必不可少的 那我们怎么来 ...
- Linux下Qt+CUDA调试并运行
Qt与CUDA相结合具体的操作主要修改qt项目中的配置文件pro.下面以测试的项目为例. 因为这是一个测试案例,代码很简单,下面将这几个文件的代码贴出来,方面后面对应pro文件和Makefile文件中 ...
- mui选择器和软键盘冲突解决
只需要让此节点失焦即可: onfocus="this.blur();"
- 开源API网关,你选对了么?
开源API网关,你选对了么? api网关的本质 不用扯那么多,也不用画图,一句话说清楚 api网关:流量总入口,得以集中控制! 就这么简单 api网关协议上最基本要支持HTTP 和 WebSocket ...