一.写在前面
大家好,我是一溪风月
一名前端程序员,目前在逐步走向全栈的道路,我们知道计算机中的内容无论是文字,图片,音频,视频本质上都是以二进制的形式来表示的,JavaScript可以非常直接的去处理非常直观的数据,比如字符串,我们通常展示给用户的也是这些内容,事实上在网页端,图片我们一直是交给浏览器来处理的,JS或者HTML只是负责告诉浏览器的一个图片的地址,浏览器负责获取这个图片,并最终将这个图片渲染出来,但是对于服务器来说是不一样的,在我们学习Node之后我们必须要学习这些内容,相对于前端,服务器要处理的本地文件的类型相对较多,比如某一个保存文本并不是使用utf-8进行编码的而是使用GBK,那么我们必须读取到他们的二进制数据,再通过GBK转换成相应的文字,比如我们需要读取的是一张图片数据(二进制),再通过某些手段对图片数据进行二次处理(剪裁,格式转换,旋转,添加滤镜)Node中有有一个Sharp
库就是读取图片或者传入图片的Buffer对其再进行处理,比如在Node中通过建立TCP建立长连接,TCP传输的字节流,我们需要将数据转换成字节再进行传入,并且需要知道传输的字节的大小(客户端需要根据大小来判断读取多少内容)这篇文章我们就来讲解一下和服务器数据处理相关的概念Buffer
,如果你觉得这篇文章对你有帮助不要吝啬你的👍如果你想了解更多相关的内容可以关注我的专栏Node服务端
和我一起学习,一起进步~
二.Buffer和二进制
通过上述的内容我们了解到对文件的处理其实处理的是二进制,但是我们直接处理二进制其实是非常麻烦的,所以在Node中为我们提供了一个类(事实上在其他语言中也是这样做的)这个类就是Buffer
并且它是全局的,我们可以将Buffer看作一个存储二进制的数组,这个数组的每一项可以存储8位二进制,其实就是一个字节,为什么是8位哪?
因为在计算机中很少的情况我们会直接操作一位二进制,因为一位二进制存储的数据非常有限的,所以通常会将8位合在一起作为一个单元,这个单元叫做字节(byte)也就是说1byte = 8bit
1kb = 1024byte
,1M = 1024kb
比如很多编程语言中的int
类型是4个字节,long
类型时8个字节,比如TCP传输的是字节流,在写入和读取时都需要说明字节的个数,比如RGB的值都是255,所以本质上在计算机中都是使用一个字节存储的。
三.Buffer和字符串之间的转换
我们可以直接通过Buffer
类来将字符串转换为buffer。
js
const buf = new Buffer("Hello")
console.log(buf)
但是其实在Node中并不希望我们通过这种方式来使用,我们可以通过类方法来创建使用。
js
const buf = Buffer.from("world")
console.log(buf)
// <Buffer 77 6f 72 6c 64>
💡如果你传入的是英文的话,在<Buffer 77 6f 72 6c 64>其实每一位就代表这一个英文字母的十六进制,但是如果是中文的情况下,可能使用一个字节不足以表示,可能需要3个字节才能表示一个中文汉字。
在Node中将字符串转为Buffer会经历如下的过程
js
const buf = Buffer.from("why")
console.log(buf)
// <Buffer 77 68 79>
如果你通过上述的from
方法将字符串转换为Buffer
你需要将它再转换回来的时候就需要使用toString()
但是需要注意的是编码问题,一版情况下我们使用的都是utf8
的编码,编码和解码使用的方式要保持一致,否则会出现乱码的问题。
js
const buf = Buffer.from("why","utf8")
console.log(buf)
console.log(buf.toString("utf8"))
四.Buffer的其他创建与操作
- 使用
Buffer.alloc(size)
创建固定大小的buffer
js
const buf = Buffer.alloc(8)
buf[0] = 100
buf[1] = 0x66
console.log(buf)
console.log(buf.toString())
buf[2] = 'm'.charCodeAt()
console.log(buf)
- 从文件读取Buffer进行操作
js
const fs = require("fs")
fs.readFile("./test.txt", (err, data) => {
console.log(data.toString())
// 对读取到的buffer进行操作
})
💡当我们对一个图片进行处理的时候我们就可以借助Sharp进行图片的处理,然后这个库会输出给我们一个新的Buffer,然后我们再将这个图片进行写入。
- 当然Buffer的API有很多我们可以先学习比较核心的内容,当我们遇到使用Buffer的场景再进行对应的查询。
五.Buffer的创建过程
事实上我们创建Buffer时,并不会频繁的向操作系统申请内存,它会默认先申请一个8 * 1024个字节大小的内存,也就是8kb。
六.Buffer.from源码
假如我们调用Buffer.from
来申请buffer
我们以创建字符串为例,以下是它的实现。
我们可以看到在使用Buffer.from
的时候调用了fromString
这个方法,以下是fromString
的实现
接着我们查看fromStringFast:这里做的事情是判断剩余的长度是否还足够填充这个字符串,如果不足够,那么就要通过createPool创建新的空间,如果够就直接使用,但是之后要进行poolOffset的偏移变化。
七.总结
这篇文章到这里基本就结束了🎉,这篇文章我们主要学习Buffer的概念和计算机中存储的内容的表示方式,我们具体的学习了Buffer
的常用API,在Buffer中API有很多,我们只需要记忆常用的即可,当遇到需要使用Buffer的时候可以根据具体需求去查询,在文章的最后我们简单的查看了一下Buffer创建的源码分析,了解即可,Buffer在我们对文件和图片的处理时候会使用的比较多。