Buffer的使用
1. 二进制数据
计算机中所有的内容:文字、数字、图片、音频、视频最终都会使用二进制来表示。
JavaScript可以直接去处理非常直观的数据:比如字符串,我们通常展示给用户的也是这些内容。
JavaScript不是也可以处理图片吗?
- 事实上在网页端,图片我们一直是交给浏览器来处理的;
- JavaScript或者HTML,只是负责告诉浏览器一个图片的地址;
- 浏览器负责获取这个图片,并且最终将这个图片渲染出来;
但是对于服务器来说是不一样的:
- 服务器要处理的本地文件类型相对较多;
- 比如某一个保存文本的文件并不是使用 utf-8进行编码的,而是用 GBK,那么我们必须读取到他们的二进制数据,再通过GKB转换 成对应的文字;
- 比如需要读取的是一张图片数据(二进制),再通过某些手段对图片数据进行二次的处理(裁剪、格式转换、旋转、添加滤镜),Node中有一个Sharp的库,就是读取图片或者传入图片的Buffer对其再进行处理;
- 比如在Node中通过TCP建立长连接,TCP传输的是字节流,我们需要将数据转成字节再进行传入,并且需要知道传输字节的大小(客户端需要根据大小来判断读取多少内容);
2. Buffer和二进制
对于前端开发来说,通常很少会和二进制打交道,但是对于服务器端为了做很多的功能,必须直接去操作其二进制的数据;
所以Node为了可以方便开发者完成更多功能,提供了一个类Buffer,并且它是全局的。
Buffer中存储的是二进制数据,那么到底是如何存储呢?
- 可以将Buffer看成是一个存储二进制的数组;
- 这个数组中的每一项,可以保存8位二进制: 00000000
为什么是8位呢?
- 在计算机中,很少的情况会直接操作一位二进制,因为一位二进制存储的数据是非常有限的;
- 所以通常会将8位合在一起作为一个单元,这个单元称之为一个字节(byte);
- 也就是说 1byte = 8bit,1kb=1024byte,1M=1024kb;
- 比如很多编程语言中的int类型是4个字节,long类型时8个字节;
- 比如TCP传输的是字节流,在写入和读取时都需要说明字节的个数;
- 比如RGB的值分别都是255,所以本质上在计算机中都是用一个字节存储的;
3. Buffer和字符串
https://nodejs.org/dist/latest-v16.x/docs/api/buffer.html
Buffer相当于是一个字节的数组,数组中的每一项对于一个字节的大小
如果将一个字符串放入到Buffer中,是怎么样的过程呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14let str = "Hello";
// 方式一
let buffer = new Buffer(str);
// <Buffer 48 65 6c 6c 6f>
console.log(buffer);
// Buffer() is deprecated due to security and usability issues.
// Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
// 方式二
let buffer2 = Buffer.from(str);
// <Buffer 48 65 6c 6c 6f>
console.log(buffer2);它是怎么样的过程呢?
中文存储
默认 utf-8,采用3字节编码一个汉字
1
2
3
4
5
6let str = "你好";
let buffer = Buffer.from(str);
// <Buffer e4 bd a0 e5 a5 bd>
console.log(buffer);
// 你好
console.log(buffer.toString('utf8'));不同编码
1
2
3
4
5
6str = "你好";
let buffer = Buffer.from(str,'utf16le');
// <Buffer 60 4f 7d 59>
console.log(buffer);
// `O}Y
console.log(buffer.toString('utf8'));
4. Buffer的其他创建函数
- Static method:
Buffer.alloc(size[, fill[, encoding]])
- Static method:
Buffer.allocUnsafe(size)
- Static method:
Buffer.allocUnsafeSlow(size)
- Static method:
Buffer.byteLength(string[, encoding])
- Static method:
Buffer.compare(buf1, buf2)
- Static method:
Buffer.concat(list[, totalLength])
- Static method:
Buffer.from(array)
- Static method:
Buffer.from(arrayBuffer[, byteOffset[, length]])
- Static method:
Buffer.from(buffer)
- Static method:
Buffer.from(object[, offsetOrEncoding[, length]])
- Static method:
Buffer.from(string[, encoding])
- Static method:
Buffer.isBuffer(obj)
- Static method:
Buffer.isEncoding(encoding)
5. Buffer.alloc
创建了一个8位长度的Buffer,里面所有的数据默认为00;
1 | const br = Buffer.alloc(8); |
6. Buffer和文件读取
6.1. 读取文件
1 | const fs = require("fs"); |
6.2. 读取图片
1 | // 图片 |
6.3. 复制图片
1 | fs.readFile("./back.jpg",(err,data)=>{ |
6.4. 操作图片sharp
https://github.com/lovell/sharp
https://www.npmjs.com/package/sharp
下载sharp模块
1 | npm i sharp |
无法下载
1 | npm ERR! sharp: Installation error: connect ETIMEDOUT 20.205.243.166:443 |
改用cnpm
1 | cnpm i sharp |
裁剪图片成 500x500
1 | const sharp = require("sharp"); |
7. Buffer的创建过程
创建Buffer时,并不会频繁的向操作系统申请内存,它会默认先申请一个8 * 1024个字节大小的内存, 也就是8kb
https://github.com/nodejs/node/blob/main/lib/buffer.js
1 | Buffer.poolSize = 8 * 1024; |
8. 源码
8.1. Buffer.from源码
1 | /** |
8.2. fromString的源码
1 | function fromString(string, encoding) { |
8.3. fromStringFast 源码
1 | function fromStringFast(string, ops) { |