Node-Buffer基本理解与使用

前言


😀我们在做前端开发的时候,我们基本不涉及处理二进制的数据,但是在Node中我们在很多时候是需要进行二进制的处理的,这个时候我们就会涉及到Buffer和数据流的内容,服务器需要处理的文件比较多

  1. 比如我们在保存一个文件使用的不是UTF-8编码而是使用的GBK编码方式,,那么我们就需要首先读取二进制数据然后再转换为UTF8的编码。
  2. 比如我们需要读取一张图片的(二进制),而是通过图片对二进制的数据进行处理(剪裁,格式转换,添加滤镜)Node中有一个sharp库就是读取图片的二进制或者传入图片的Buffer对其进行处理。
  3. 比如在Node中通过TCP建立长链接,TCP传输的是字节流,我们需要将数据转换成字节再传入,并且知道字节的大小。

🤡buffer是什么?buffer被翻译为缓冲区,buffer其实就是一个交接计算机世界和人类世界的桥梁,二进制通过buffer能够转为人类能看得懂的东西,比如字符串,数字,举一个更加简单的例子,我们使用翻译器将英文翻译成中文,翻译器其实就是buffer。

一.了解buffer


😈经过上面的了解,我们知道了buffer大概是一个什么样的作用,其实在我们实际使用buffer的时候我们一般把buffer看做是一个存储二进制的数组,在这个数组中每一项可以保存八位二进制。

🥺为什么是8为哪?二进制不应该是010101这种样子的吗?为什么在buffer中是一位表示8位哪?

  1. 在计算机中我们很少情况会直接操作二进制数据,因为一位存储二进制是非常有限的
  2. 所以通常会把八位合并在为一个单元,这个单元称为字节。
  3. 也就是1byte = 8bit
  4. 比如在很多其他编程语言中int类型是四个字节,long类型是8个字节。
  5. 比如TCP传输的是字节流,在写入和读取的时候都需要说明字节的个数。
  6. 比如RGB的值分别都是255,所以在计算机中就是用了一个字节存储的。
  7. buffer的一位就是一个字节比如 [11111111,00000000]

🐻如果不太熟悉进制之间的换算,我们可以去了解下各种进制之间是如何换算的,但是我建议我们可以直接使用电脑上的计算器来进行进制之间的转换,当我们选择二进制输入之后就会得到其他进制的结果,我们解释下计算器不同进制的符号。

  1. HEX:表示十六进制(Hexadecimal),也称为基数为16的数字系统。它使用0-9的十个阿拉伯数字和A-F的六个字母(代表10-15)来表示数字。例如,十进制的数字15在十六进制中表示为F。
  2. DEC:表示十进制(Decimal),也称为基数为10的数字系统。它使用0-9的十个阿拉伯数字来表示数字。例如,十进制的数字15在十进制中表示为15。
  3. OCT:表示八进制(Octal),也称为基数为8的数字系统。它使用0-7的八个阿拉伯数字来表示数字。例如,十进制的数字15在八进制中表示为17。
  4. BIN:表示二进制(Binary),也称为基数为2的数字系统。它使用0和1两个数字来表示数字。例如,十进制的数字15在二进制中表示为1111。

😈十六进制经常用于表示内存地址、颜色值等;八进制和二进制常用于表示文件权限、数据存储等。在编程和计算机系统中,我们经常需要在不同进制之间进行转换和操作,当然在buffer中表示的方法是将四位的二进制用十六进制来表示

js 复制代码
bin:[1111 1111] ----> buffer: [ff]

二.buffer的基本使用


🥺buffer的初始化使用

js 复制代码
const buf = new Buffer("HelloWorld") // 不推荐使用这种方法创建
console.log(buf)

// 创建Buffer
const buf2 = Buffer.from("world")
console.log(buf2)

// 创建buffer包含中文
const buf3 = Buffer.from("你好啊")
console.log(buf3)

😈buffer和字符串,我们知道buffer相当于是一个字节数组,数组中的每一项对应一个字节的大小,那么如果我们把一个字符串放入buffer是怎样的过程哪?

如果将字符串转成buffer首先英文字符串会通过ASCII编码转为十六进制数据,然后将十六进制数据进行存储在二进制数组中也就是buffer中。

那么如果我们想把转为buffer的数据再转换回来我们应该如何做哪?其实buffer中也提供了将字符串转换回来的方法toString()我们使用这个方法可以将buffer转为普通的字符串。

js 复制代码
const buf3 = Buffer.from("你好啊")
console.log(buf3)
console.log(buf3.toString())

👹手动指定创建buffer过程的编码,我们在上述进行创建buffer的时候默认让buffer进行自动进行编码的,但是我们其实也可以自己指定,但是要注意的是我们使用什么样的方式编码就要使用什么样的方式解码,否则会出现问题的,但是其实在开发过程中我们尽量使用buffer的默认编码,buffer的默认编码使用的是utf8的方式。

js 复制代码
const buf = Buffer.from("你好啊","utf8")
console.log(buf.toString('utf8'))

😊创建一个8个字节大小的buffer对象。

js 复制代码
const buf  = Buffer.alloc(8)
console.log(buf)
// 手动对每个字节进行操作
console.log(buf[0])
console.log(buf[1])
// 对buffer进行赋值
buf[0] = 100  // 会进行转换为16进制
buf[1] = 0x66
// 转为字符串
buf[1] = 102
console.log(buf.toString())

当我们需要对单个字符进行编码的时候我们需要charCodeAt()方法进行编码

js 复制代码
const buf = Buffer.alloc(8)
buf[0] = 'm'.charCodeAt()
console.log(buf[0]) // 输出结果

三.从文件中读取buffer


js 复制代码
fs.readFile('./aaa.txt',(err,data)=>{
  console.log(data.toSting())
})

🤡在计算机中的底层都是二进制数据的方式,无论是图片还是其他文件,我们首先来读取一个图片的二进制数据

js 复制代码
fs.readFile('./aaa.png',(err,data)=>{
  console.log(data)
})

三.buffer的创建过程


事实上我们在创建buffer时,并不会频繁的向操作系统申请内存,它会默认先申请一个8*1024个字节大小的内存,也就是8kb,也就是8*1024byte,这个其实buffer做的一个性能优化,buffer的内存增加策略是

  1. 这里做的事情就是判断剩余的长度是否还足够填充这个字符串。
  2. 如果内存不够,那么就通过createPool创建新的空间。
  3. 如果够就直接使用,但是之后要进行poolOffset的偏移变化。

四.总结


😀buffer是一个存储二进制的数组,我们可以理解为一个转换中英文的转换器的角色,但是buffer存储的时候不会直接以二进制的方式进行存储,而是会把8个bit为每4为一个单位进行存储,在内存中buffer会首先申请一个8kb的内存空间,创建buffer的方式Buffer.from(),申请固定buffer的长度Buffer.alloc(8),并且可以将文件读取为二进制,在服务端开发中我们会经常用到buffer~

相关推荐
海里真的有鱼1 分钟前
Spring Boot 项目中整合 RabbitMQ,使用死信队列(Dead Letter Exchange, DLX)实现延迟队列功能
开发语言·后端·rabbitmq
工业甲酰苯胺12 分钟前
Spring Boot 整合 MyBatis 的详细步骤(两种方式)
spring boot·后端·mybatis
新知图书1 小时前
Rust编程的作用域与所有权
开发语言·后端·rust
wn5312 小时前
【Go - 类型断言】
服务器·开发语言·后端·golang
希冀1232 小时前
【操作系统】1.2操作系统的发展与分类
后端
GoppViper3 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文4 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people4 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
罗政9 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
拾光师11 小时前
spring获取当前request
java·后端·spring