一、数据的二进制

计算机中所有的内容:文字、数字、图片、音频、视频最终都会使用二进制来表示。

  • JavaScript可以直接去处理非常直观的数据:比如字符串,我们通常展示给用户的也是这些内容。

不对啊,JavaScript不是也可以处理图片吗?

  • 事实上在网页端,图片我们一直是交给浏览器来处理的;
  • JavaScript或者HTML,只是负责告诉浏览器一个图片的地址;
  • 浏览器负责获取这个图片,并且最终讲这个图片渲染出来;

但是对于服务器来说是不一样的:

服务器要处理的本地文件类型相对较多;

  • 比如某一个保存文本的文件并不是使用 utf-8进行编码的,而是用 GBK,那么我们必须读取到他们的二进制数据,再通过GKB转换成对应的文字;
  • 比如我们需要读取的是一张图片数据(二进制),再通过某些手段对图片数据进行二次的处理(裁剪、格式转换、旋转、添加滤镜),Node中有一个Sharp的库,就是读取图片或者传入图片的Buffer对其再进行处理;
  • 比如在Node中通过TCP建立长连接,TCP传输的是字节流,我们需要将数据转成字节再进行传入,并且需要知道传输字节的大小(客服端需要根据大小来判断读取多少内容);

二、Buffer与二进制

我们会发现,对于前端开发来说,通常很少会和二进制打交道,但是对于服务器端为了做很多的功能,我们必须直接去操作其二进制的数据;

  • 所以Node为了可以方便开发者完成更多功能,提供给了我们一个类Buffer,并且它是全局的。
  • 我们前面说过,Buffer中存储的是二进制数据,那么到底是如何存储呢?
  • 我们可以将Buffer看成是一个存储二进制的数组;
  • 这个数组中的每一项,可以保存8位二进制: 00000000

为什么是8位呢?

  • 在计算机中,很少的情况我们会直接操作一位二进制,因为一位二进制存储的数据是非常有限的;
  • 所以通常会将8位合在一起作为一个单元,这个单元称之为一个字节(byte)
  • 也就是说 1byte = 8bit,1kb=1024byte,1M=1024kb;
  • 比如很多编程语言中的int类型是4个字节,long类型时8个字节;
  • 比如TCP传输的是字节流,在写入和读取时都需要说明字节的个数;
  • 比如RGB的值分别都是255,所以本质上在计算机中都是用一个字节存储的;

三、Buffer与字符串

Buffer相当于是一个字节的数组,数组中的每一项对于一个字节的大小:

如果我们希望将一个字符串放入到Buffer中,是怎么样的过程呢?

1
2
3
4
5
6
//这种方式不被推荐
//const buffer = new Buffer('why')

//使用这种方式创建
const buffer = Buffer.from('why')
console.log(buffer)

如果是中文字符呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const msg = '你好';

//默认utf8编码,一中文字符=3字节存储
const buffer = Buffer.from(msg);
console.log(buffer);
//解码
console.log(buffer.toString()); //你好

//utf16le编码,一中文字符=2字节存储
const buffer1 = Buffer.from(msg, 'utf16le');
console.log(buffer1);

//如果编码解码方式不同会乱码
const buffer2 = Buffer.from(msg);
console.log(buffer.toString('utf16le')); //뷤붥

四、Buffer的其他创建方式

可参考官方文档

Buffer.alloc

1
2
3
4
5
6
7
8
9
10
11
12
13
const buffer = Buffer.alloc(8)
console.log(buffer); //<Buffer 00 00 00 00 00 00 00 00>

//Buffer默认是以16进制进行存储,88转为16进制就是58
buffer[0] = 88
console.log(buffer); //<Buffer 58 00 00 00 00 00 00 00>

//如果想直接存58,可以写成16进制格式
buffer[1] = 0x88
console.log(buffer); //<Buffer 58 88 00 00 00 00 00 00>

console.log(buffer[0].toString(10)); //88
console.log(buffer[0].toString(2)); //1011000

五、Buffer文件操作

文本

1
2
3
4
5
6
7
const fs = require('fs');

fs.readFile('./foo.txt', (err,data) => {
console.log(data); //<Buffer e4 bd a0 e5 a5 bd>
console.log(data.toString()); //你好

});

图片

1
2
3
4
5
6
fs.readFile('./foo.jpg',(err,data) => {
//一堆码
console.log(data);
//一堆乱码
console.log(data.toString());
})

sharp库的使用

1
2
3
4
5
6
7
8
9
sharp(
'./foo.jpg',
resize(200, 200)
.toBuffer()
.then((data) => {
fs.writeFile('./bar.jpg', data);
})
);

六、Buffer创建过程

事实上我们创建Buffer时,并不会频繁的向操作系统申请内存,它会默认先申请一个8 * 1024个字节大小的内存,也就是8kb。

相关源码: