深入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 ...
随机推荐
- C# dotnet 获取整个局域网的 ip 地址
局域网可以使用的 IP 地址有很多,我写了一段代码用来枚举所有可以用的 ip 地址 小伙伴都知道,局域网可以使用的 IP 范围如下 A类地址:10.0.0.0 - 10.255.255.255 B类地 ...
- BZOJ 3166
BZOJ3196: Tyvj 1730 二逼平衡树 传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题意: 1.查询k在区间内的排名 ...
- Android SDK目录具体结构及Android源码的具体结构
Android SDK目录具体结构 1. add-ons:这里面保存着附加库,比如Google Maps,当然你如果安装了OphoneSDK,这里也会有一些类库在里面. 2. docs:这里面是And ...
- js中时间戳转换成xxxx-xx-xx xx:xx:xx类型日期格式的做法
1.十三位数字的时间戳转换方法 var time = new Date(datetime).toLocaleString().replace(/年|月/g, "-").replac ...
- nginx负载均衡的相关配置
一台nginx的负载均衡服务器(172.25.254.131) 两台安装httpd作为web端 一.准备工作 1.1 安装nginx yum -y install gcc openssl-devel ...
- ulimit -u 解决 Jenkins OOM 错误
Apr 24, 2018 11:19:48 AM hudson.init.impl.InstallUncaughtExceptionHandler$DefaultUncaughtExceptionHa ...
- $CH0601\ Genius\ ACM$ 倍增优化DP
ACWing Description 给定一个长度为N的数列A以及一个整数T.我们要把A分成若干段,使得每一段的'校验值'都不超过N.求最少需要分成几段. Sol 首先是校验值的求法: 要使得'每对数 ...
- 突破CRUD | 简单优雅的代码生成工具诞生记(万字长文慎入)
0.学习本文你或许可以收获 1.一个需求从产生.分析到解决的全过程思考2.简单的面向对象分析实践3.UML类图实践4.设计模式的实践应用5.最后收获一款还算不错的代码生成工具实现思路和源代码 本文将从 ...
- Redis 持久化的两种方案
reids是一个key-value存储系统,为了保证效率,缓存在内存中,但是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,以保证数据的持久化. 所以:redis是一个支持持 ...
- MySQL 持久化保障机制-redo 日志
我们在 聊一聊 MySQL 中的事务及其实现原理 中提到了 redo 日志,redo 日志是用来保证 MySQL 持久化功能的,需要注意的是 redo 日志是 InnoDB 引擎特有的功能. 为什么 ...