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 的过程中,需要特别注意共享和拷贝的区别,发生错误比较难排查。

参考链接

最后

  1. 觉得不错,帮忙点个推荐呗,您的支持是对我最大的激励
  2. 欢迎我的公众号:「心谭博客」,只专注于前端 + 算法的原创分享

由于个人精力有限,很多系列和历史文章没有即时同步,请前往「前端图谱」&「算法题解」,保证您有所收获。

深入Node模块Buffer-学会操作二进制的更多相关文章

  1. node.js—Buffer类(二进制数据处理模块)

    Buffer类概述 一个用于更好的操作二进制数据的类 我们在操作文件或者网络数据的时候,其实操作的就是二进制数据流 Node为我们提供了一个更加方便的去操作这种数据流的类 Buffer,他是一个全局的 ...

  2. node的buffer模块

    Buffer这块很早前就想留一篇笔记.前端JS处理buffer的场景其实并不多,虽然后来基于webGL与显卡通信的需求增加了二进制数组,但毕竟相对小众. Buffer的含义是,在数据传输时用内存中的一 ...

  3. Node.js缓冲模块Buffer

    前言 Javascript是为浏览器而设计的,能很好的处理unicode编码的字符串,但对于二进制或非unicode编码的数据就显得无能为力. Node.js继承Javascript的语言特性,同时又 ...

  4. Node.js之使用Buffer类处理二进制数据

    Node.js之使用Buffer类处理二进制数据 Buffer类可以在处理TCP流或文件流时处理二进制数据,该类用来创建一个专门存放二进制数据的缓存区. 1. 创建Buffer对象 1.1 直接创建: ...

  5. node使用buffer生成图片

    buffer是node里的一个模块,这个模块的出现是因为js没有阅读和操作二进制数据流而出现的 buffer是什么及作用? Buffer顾名思义叫缓冲区,用于存储速度不同步的设备或优先级不同的设备之间 ...

  6. 模块机制 之commonJs、node模块 、AMD、CMD

    在其他高级语言中,都有模块中这个概念,比如java的类文件,PHP有include何require机制,JS一开始就没有模块这个概念,起初,js通过<script>标签引入代码的方式显得杂 ...

  7. Node.js Buffer(缓冲区)

    JavaScript 语言自身只有字符串数据类型,没有二进制数据类型. 但在处理像TCP流或文件流时,必须使用到二进制数据.因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门 ...

  8. node 之 Buffer 笔记

    1. Buffer 相关 js 最初是被设计来处理 html的,因此它不善于处理二进制数据,只有数值和字符串类型.而 node 是基于 js 的,因为 node 需要实现一些譬如数据库通信.操作图像及 ...

  9. nodeJS-使用buffer类处理二进制数据

    使用buffer类处理二进制数据 在客户端javascript脚本代码中,对于二进制数据并没有提供一个很好的支持.然后在nodejs中需要处理像TCP流或文件流时,必须要处理二进制数据.因此在node ...

随机推荐

  1. Centos6.5_x64-GitLab搭建私有GitHub

              GitLab,是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. 它拥有与GitHub类似的功 ...

  2. Team Foundation Server 2015使用教程【6】:新增权限为读取器的团队

  3. spring boot 实践总结(转)

    pring Boot是最流行的用于开发微服务的Java框架.在本文主要分享的是在专业开发中使用Spring Boot所采用的最佳实践.这些内容是基于个人经验和一些熟知的Spring Boot专家的文章 ...

  4. .NET ORM 开源项目 FreeSql 1.0 正式版发布

    一.简介 FreeSql 是 .NET 平台下的对象关系映射技术(O/RM),支持 .NetCore 2.1+ 或 .NetFramework 4.0+ 或 Xamarin. 从 0.0.1 发布,历 ...

  5. 机器学习- Numpy基础 吐血整理

    Numpy是专门为数据科学或者数据处理相关的需求设计的一个高效的组件.听起来是不是挺绕口的,其实简单来说就2个方面,一是Numpy是专门处理数据的,二是Numpy在处理数据方面很牛逼(肯定比Pytho ...

  6. 020 ceph作openstack的后端存储

    一.使用ceph做glance后端 1.1 创建用于存储镜像的池 [root@serverc ~]#  ceph osd pool create images 128 128 pool 'images ...

  7. Kerrigan:配置中心管理UI的实现思路和技术细节

    去年写过一篇文章『中小团队落地配置中心详解』,介绍了我们借助etcd+confd实现的配置中心方案,这是一个对运维友好,与开发解耦的极佳方案,经过了一年多的实践也确实帮我们解决了配置文件无版本.难回滚 ...

  8. 洛谷$P$3241 开店 $[HNOI2015]$ 主席树/点分治

    正解:主席树/动态点分治 解题报告: 传送门! $umm$淀粉质的话要是动态的我还不会$QAQ$,,,所以先写下主席树的题解昂$QwQ$ 题目大意是说,给定一棵树,树上每个点都有个值,然后有若干个询问 ...

  9. 分支结构,for循环,while循环,跳出循环

    #流程控制 概念:通过规定的语句让程序代码有条件的按照一定的方 式执行 顺序结构 按照书写顺序来执行,是程序中最基本的流程结构 选择结构(分支结构.条件结构) 分支结构 单路分支:if(执行的条件){ ...

  10. 「算法竞赛进阶指南」0x01 位运算 知识笔记

    二进制是计算机的根本! 你了解她它吗? int lowbit(int x) { return x&(-x);//x&(~x+1),~x=-1-x; } int __builtin_ct ...