0
点赞
收藏
分享

微信扫一扫

Node.js Buffer 对象

前言

计算机底层存储的数据都是二进制的。在前端开发中一般都是实现页面效果,很少会直接操作二进制的数据。而在 Node.js 擅长的领域,比如在服务端程序开发中,经常会读取文件,处理文件,和二进制数据打交道比较多。

​Buffer​​ 对象是 Node.js 提供的一个全局对象,专门用来处理二进制数据

二进制数据在开发中,操作和表示都非常不方便,所以 Buffer 对象采用十六进制来表示二进制数据。比如二进制数据 ​​00001111​​,转为十六进制就是 ​​f​​。用 buffer 表示就是:

let buffer = Buffer.from([0b1111])
console.log(buffer) // <Buffer 0f>

创建 buffer

Buffer 既然是一个对象,那么一般可以通过 new 的方式创建它的实例:

let buffer = new Buffer()

但是这种方式由于安全性已经废弃了。在实例化时会报错。

文档推荐使用这几种新的方法来创建:

  • Buffer.alloc:创建指定字节大小的 buffer。
  • Buffer.allocUnsafe:从名字看就知道是一个不安全的 API 。不推荐使用。
  • Buffer.from:使用传入的数据创建 buffer,最常用的方法。

Buffer.alloc

创建 buffer 的时候需要指定 buffer 的大小。

// 创建一个 3 字节大小的buffer
let buffer = Buffer.alloc(3)
console.log(buffer)

// buffer 使用十六进制来描述二进制数据,长这样:
// 由于没有往里存东西,所以都为 00
// <Buffer 00 00 00>

Buffer.allocUnsafe

let buffer = Buffer.allocUnsafe(3)
console.log(buffer) // 值不确定

为什么值不确定呢?

由于 V8 引擎的 GC 机制,会产生内存碎片,一块空间不再使用了,但是还没有被回收。此时就有可能会被这个方法拿来创建一个 buffer ,所以创建出来的 buffer 可能并不是空的。这就是为什么值不确定的原因。同样也是不推荐使用该方法的原因。 其实该方法也谈不上不安全,只是不干净而已,并不影响最终的使用,因为创建之后总会用新的数据覆盖它。

Buffer.from

该方法接收两个参数,第一个参数是用来创建 buffer 的数据,也就是要存到缓冲区的数据,有三种类型:字符串,数组和 Buffer 实例

第二个参数用来指定编码格式,默认为 ​​utf-8​​。

使用字符串创建 buffer

let buffer1 = Buffer.from('abc')
console.log(buffer1)

// 默认使用 utf-8 编码,一个字符占一个字节,所以有三个字节大小
// <Buffer 61 62 63>


let buffer2 = Buffer.from('昆吾')
console.log(buffer2)

// 默认使用 utf-8 编码,一个汉字占3个字节。所以所以生成的 buffer有6个字节
// <Buffer e6 98 86 e5 90 be>

使用数组创建 buffer

数组里可以放二进制,十进制,八进制,十六进制,字符串。

let buffer1 = Buffer.from([1, 2, 3])
let buffer2 = Buffer.from([0x4, 0x5, 0x6])
let buffer3 = Buffer.from([0b111, 0b1000, 0b1001])
console.log(buffer1)
console.log(buffer2)
console.log(buffer3)

/*
<Buffer 01 02 03>
<Buffer 04 05 06>
<Buffer 07 08 09>
*/

使用 buffer 创建 buffer

let buffer1 = Buffer.alloc(3)
let buffer2 = Buffer.from(buffer1)
console.log(buffer1)// <Buffer 00 00 00>
console.log(buffer2)// <Buffer 00 00 00>

创建出来的两个 buffer 长的一样,但是两块独立的内存空间,互不影响。

Buffer 的实例方法

观察上文中创建的 buffer,比如 ​​<Buffer 01 02 03>​​,非常像是一个数组。

我们可以将 buffer 看作是一个存放二进制数据的数组,只不过每一项都是一字节大小的数据,而非我们熟悉的数字、字符串等。

Buffer 是一个全局对象,打印一下它的原型对象:

console.log(Buffer.prototype)

Node.js Buffer 对象_Node.js

Node.js Buffer 对象_Buffer_02

观察可知,它继承自 ​​Uint8Array​​ 对象,并且有非常多的原型方法。我们主要学习一些常用的,包括 ​​copy​​、​​toString​​、​​indexOf​​、​​includes​​、​​fill​​、​​write​​、​​subarray​​ 等。

toString

将从 buffer 中读取出来的数据转为字符串类型。

接收三个可选参数,分别是编码格式,从 buffer 中读取数据的起始位置。

let buffer = Buffer.from('昆吾kw')

console.log(buffer) // <Buffer e6 98 86 e5 90 be 6b 77>
console.log(buffer.toString()) // 昆吾kw 读取全部数据转为字符串
console.log(buffer.toString('utf8', 6)) // kw 从第7个字节开始读取
console.log(buffer.toString('utf8', 0, 6)) // 昆吾 读取第1个到第6个字节

我们发现,buffer 在使用时和数组非常像,也可以通过从0开始的索引来指定位置,0索引表示的就是第一个字节。后面的示例中我们以此表示。

copy

把 buffer 中的数据拷贝到另一个 buffer 中。

接收四个参数,第一个为拷贝数据的目标 buffer,必填。第二个参数是目标 buffer 从哪个位置开始接收接收数据。后两个参数指定从源 buffer 中取数据的起始位置。

let target = Buffer.alloc(8)

let source = Buffer.from('昆吾kw')


// 部分拷贝。将 source 中 0-5 个字节也就是“昆吾” 拷贝至 target 中,target 从 0 位置开始接收
source.copy(target, 2, 0, 6)
console.log(target) // <Buffer 00 00 e6 98 86 e5 90 be>
console.log(target.toString()) // 昆吾

// 完整拷贝。将 source 中的数据拷贝到 target 中。
source.copy(target)
console.log(target.toString()) // 昆吾kw

indexOf

类似字符串和数组中的 indexOf 方法,用于查找目标中匹配到的第一个元素的位置。

在 buffer 中,就是找匹配到的字节的位置。

接收两个参数。第一个是要查找的内容,第二个指定从 buffer 的哪个字节开始查找。找到了则返回字节的位置,找不到返回 -1。

let buffer = Buffer.from('hello, world')

console.log(buffer) // <Buffer 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64>

console.log(buffer.indexOf('l')) // 返回找到的第一个匹配的字节位置
console.log(buffer.indexOf('l', 3)) // 从 buffer 的第4个字节开始查找。
console.log(buffer.indexOf('a')) // -1 。 若找不到返回 -1

includes

判断 buffer 中是否包含指定的数据。类似于数组的 includes 方法。

接收两个参数。第一个是要查找的内容,第二个指定从 buffer 的哪个字节开始查找。若 buffer 中包含,则返回 true,不包含返回false。

let buffer = Buffer.from('hello, world')

console.log(buffer.includes('l')) // true
console.log(buffer.includes('a')) // false

​includes​​ 方法和 ​​indexOf​​ 方法的作用是一样的,都是用于查找一个目标数据。

fill

向 buffer 中填充数据。

接收4个参数,第一个是要填充进 buffer 的数据。第二、三个参数分别表示 buffer 接收数据的起始位置。第四个参数设置编码格式,默认为 ​​utf8​​。

let buffer = Buffer.alloc(8)

// 将 '123' 填充到 buffer 中,从第三个字节开始填充,直到填满
buffer.fill('123', 2)
console.log(buffer) // <Buffer 00 00 31 32 33 31 32 33>
console.log(buffer.toString()) // 123123

// 将 '123' 填充到 buffer 中,默认填满
buffer.fill('123')
console.log(buffer) // <Buffer 31 32 33 31 32 33 31 32>
console.log(buffer.toString()) // 12312312

write

向 buffer 中写入数据。

接收三个参数。第一个是写入的数据,第二、三个分别是 buffer 接收数据的起始位置。第四个参数设置编码格式,默认为 ​​utf8​​。

let buffer = Buffer.alloc(6)

// 将 '123' 写入到 buffer 中,数据有多少就写入多少
buffer.write('123')
console.log(buffer) // <Buffer 31 32 33 00 00 00>
console.log(buffer.toString()) // 123

// 将 '123' 填充到 buffer 中,从第三个字节开始填充,数据有多少写入多少
buffer.write('123', 3)
console.log(buffer) //<Buffer 31 32 33 31 32 33>
console.log(buffer.toString()) // 123123

​write​​ 和 ​​fill​​ 的区别:前者是数据有多少往 buffer 中写入多少,而 ​​fill​​ 是重复写入,直到填满整个 buffer。

subarray

从 buffer 中截取数据并返回一个新的 buffer。

在数组和字符串的原型方法中,截取数据的方法叫作 slice。而 Buffer 对象中的 slice 方法已经废弃,改用 ​​subarray​​。

该方法接收4个参数,第一个是要填充进 buffer 的数据。第二、三个参数分别表示 buffer 接收数据的起始位置。第四个参数设置编码格式,默认为 ​​utf8​​。

let buffer = Buffer.from('123456')

// 截取 buffer 的全部数据
let subBuffer1 = buffer.subarray()

// 截取 buffer 的前三个字节
let subBuffer2 = buffer.subarray(0, 3)

console.log(buffer) // <Buffer 31 32 33 34 35 36>
console.log(subBuffer1) // <Buffer 31 32 33 34 35 36>
console.log(subBuffer2) // <Buffer 31 32 33>

Buffer 的静态方法

Buffer的静态方法我们已经学过三个了,就是用来创建 buffer 的 ​​alloc​​ 、​​allocUnSafe​​ ​​from​​ 方法。

Buffer.concat

将多个 buffer 拼接成一个新的 buffer。就类似数组中的 ​​concat​​ 方法。用的非常多。

let buffer1 = Buffer.from('昆吾')
let buffer2 = Buffer.from('kw')

console.log(Buffer.concat([buffer1, buffer2]))

// 第二个参数指定生成新的 buffer 的长度
console.log(Buffer.concat([buffer1, buffer2], 7))

// <Buffer e6 98 86 e5 90 be 6b 77>
// <Buffer e6 98 86 e5 90 be 6b>

Buffer.isBuffer

这个很好理解,见名知义,用来判断数据是否是 buffer 类型。

let buffer = Buffer.from('1')

console.log(Buffer.isBuffer(1)) // false
console.log(Buffer.isBuffer(buffer)) // true

总结

本文简单介绍了 Node.js 中 Buffer 对象的使用,包括创建实例 buffer 的方法,以及操作 buffer 的常用方法。

创建 buffer 主要使用两个方法:

  • Buffer.alloc:创建一个固定字节大小的内存空间
  • Buffer.from:将传入的数据转为二进制放到内存中,用法有很多

操作 buffer 的方法包括 Buffer 原型对象上的实例方法和 Buffer 类的静态方法:

  • toString:读取 buffer 中的数据,转为字符串
  • copy:拷贝 buffer 中的数据到另一个 buffer 中
  • indexOf:查找 buffer 中是否有目标内容
  • includes:作用和 indexOf 相同,返回结果不同
  • fill:向 buffer 中填充数据
  • write:向 buffer 中写入数据
  • subarray:从 buffer 中截取数据
  • Buffer.concat:拼接 buffer
  • Buffer.isBufer:判断 buffer 类型

方法比较多,而且不常用,有印象即可。本文可作为文档使用,以供需要时翻看。

举报

相关推荐

0 条评论