初学Nodejs(2):Buffer缓冲区

Buffer缓冲区

1、概述

1.1 简介

Buffer是nodejs全局上的一个内置模块,可以直接在不用引入就可以直接调用的模块。

buffer的结构和数组很像,操作的方法也和数组类似。但普通数组类型不能存储音频,视频,图片等二进制文件,Buffer就是用来解决这个问题的。

Buffer能够让javascript直接操作二进制数据,因此Buffer常常和流、管道、IO联系在一起。

当我们需要使用图片、文件、视频这些二进制资源的时候,基本的操作过程就是拿数据,将数据提供给程序并传到具体的应用上,并且应用也并不一定是直接使用传过来的二进制数据,可能还需要换成另一种编码格式的数据,并且在进行转码后这个数据还需要一直保存这种编码格式一段时间,直到应用不再使用这个数据而被系统回收为止。

可以看到,上述过程说到需要“保持这种编码格式一段时间”,其实就是说需要一个存放这个数据的物理资源,也就是说缓存,而Buffer就作为这个缓存。

简单来说buffer就是专门用来存储二进制文件的数组

1.2 Buffer模块的结构

Buffer作为nodejs全局作用上的一个模块,可以理解为它是全局上的一个属性,这个属性引用着Buffer模块对象,从这角度来说他是一个javascript模块,但javascript自身并不具备直接操作二进制文件的能力,而实际上Buffer在nodejs底层上还有一个C++模块,由于IO操作很好性能,所以Buffer模块的部分性能使用C++实现的

1.3 Buffer对象的结构

前面说过,Buffer和数组非常相似,他的元素为16进制的两位数,也就是0~255之间的数值。

let str = "nodejs的学习路径";
let buf = new Buffer(str,'utf-8');
console.log(buf);
//打印结果:<Buffer 6e 6f 64 65 6a 73 e7 9a 84 e5 ad a6 e4 b9 a0 e8 b7 af e5 be 84>

不同编码的字符占用的元素各不相同,utf-8编码汉字占用3个元素,字母和半角标点符号占用1个元素,所以上面的str转成Buffer由21个元素组成。
并且Bufferr也可以和数组一样通过下标访问元素。

let str = "nodejs的学习路径";
let buf = new Buffer(str,'utf-8');
console.log(buf.length);    //21
console.log(buf[3]);        //101

前面说过,他只会取16进制的数据,也就是0~255之间的数,那么如果不取值的时候结果是什么?如果取得值超过了16进制取值范围会发生什么?

let buf = new Buffer(10);
console.log(buf[10]);//undefined
buf[0] = -10;
buf[1] = -260;
buf[2] = 260;
buf[3] = 515;
console.log(buf) //<Buffer f6 fc 04 03 00 00 00 00 00 00>

可以看到,当不取值时,会默认为00,如果取值超过了256,那么就减n个256,直到这个取值范围在0 ~255之间,例如260就是260-256=4,结果为04;如果取值小于0,那么就加n个256,直到取值范围在0 ~255之间,例如-260就是-260+256+256 = 252

1.4 Nodejs中支持的字符编码

  • ascii - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。

  • utf8 - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。

  • utf16le - 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。

  • ucs2 - utf16le 的别名。

  • base64 - Base64 编码。

  • latin1 - 一种把 Buffer 编码成一字节编码的字符串的方式。

  • binary - latin1 的别名。

  • hex - 将每个字节编码为两个十六进制字符。

2、Buffer对象API

2.1 创建对象

2.1.1 构造方法new Buffer()(已废弃)
// (1) new Buffer(size)  
// 传入一个size表示创建一个size字节大小的buffer实例对象
var buf = new Buffer(10); // 传入一个size表示创建10个字节大小的buffer数组,取值默认全为0
console.log(buf[0]); // 0
console.log(buf[9]); // 0

// ============================
// (2)new Buffer(array)
// 传入一个array数组
var arr = [10,20,30,40] 
var buf = new Buffer(arr)
console.log(buf); // <Buffer 0a 14 1e 28>
console.log(buf[0]); // 10
console.log(buf[1]); // 20

// ============================
// (3) new Buffer(arrayBuffer[,byteOffset[,length]])
// 第一个参数:底层ArrayBuffer对象,该参数是必需的。
//第二个参数:视图开始的字节序号,默认从0开始。非必须
//第三个参数:视图包含的数据个数,默认直到本段内存区域结束,非必须
// 传入一个arrayBuffer类型的数据
const bf = new Unit16Array(4); 
var buf = new Buffer(bf)
console.log(buf); // <Buffer 00 00 00 00>

// ============================
// (4) new Buffer(buffer)
// 传入一个buffer对象,表示复制一份数据
var buf = new Buffer(10); // 创建一个size=10大小的buffer对象实例
var buf2 = new Buffer(buf) // 复制一份buf实例
console.log(buf2);

// ============================
// (5) new Buffer(string[,encoding])
// 传入一个字符串
var buf = new Buffer("name")
console.log(buf); // <Buffer 6e 61 6d 65> // 16进制
console.log(buf[0]); // 110 // n对应的Ascii码
console.log(buf.toString()); // name 

目前node官网已经不推荐使用buffer的构造函数创建buffer对象了,如果继续使用构造函数创建buffer,则会报如下警告:[DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

2.1.2 静态方法Buffer.from()(推荐)
// =======================
// Buffer.from(string[,encoding])
var str = 'Hello World';
// 将一个字符串保存到buffer中
var buf = Buffer.from(str);
console.log(buf); 
// 结果:<Buffer 48 65 6c 6c 6f 20 57 6f 72 6c 64>
console.log(buf[0]) // 104 // H对应的ascii码
console.log(buf.toString()); // Hello World

// Buffer.from(array)
// 传入一个数组
let arr = [10,20,30,44]
let buf = Buffer.from(arr)
console.log(buf); // <Buffer 0a 14 1e 2c>
console.log(buf[0]); // 10
console.log(buf[3]); // 44

// Buffer.from(arrayBuffer[, byteOffset[, length]])
// 保存一个arrayBuffer类型的数据
const bf = new Uint16Array(2); 
bf[0] = 20
bf[1] = 30
const buf = Buffer.from(bf)
console.log(buf); // <Buffer 14 1e>

// Buffer.from(buffer)
const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1); // 复制一份buf1
console.log(buf1); // <Buffer 62 75 66 66 65 72>
console.log(buf2); // <Buffer 62 75 66 66 65 72>

// Buffer.from(Object[, offsetOrEncoding[, length]])
// 存入一个对象
const buf = Buffer.from(new String('this is a test'));
// Prints: <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
2.1.3 静态方法Buffer.alloc(size[, fill[, encoding]])(推荐)
// Buffer.alloc(size[, fill[, encoding]])
// 参数size:buffer数组长度;参数fill:表示用某一个数据填满这个buffer,参数encoding表示编码格式
const buf1 = Buffer.alloc(5);
console.log(buf1); // <Buffer 00 00 00 00 00>

const buf2 = Buffer.alloc(5,'a')
console.log(buf2); // <Buffer 61 61 61 61 61>
2.1.4 Buffer.allocUnsafe(size)

返回一个指定大小的 Buffer 实例,但是它不会被初始化,所以它可能包含敏感的数据。
这个方法比调用 Buffer.alloc() 更快,但返回的 Buffer 实例可能包含旧数据,因此需要使用 fill() 或 write() 重写。

var buf = Buffer.allocUnsafe(10);
buf[0] = 88; 
buf[1] = 255; // 11111111
buf[2] = 0xaa; 
buf[3] = 256; // 00000000
console.log(buf);
2.1.5 Buffer.allocUnsafeSlow(size)

返回一个指定大小的 Buffer 实例,但是它不会被初始化,所以它可能包含敏感的数据,和allocUnsafe(size)差不多

2.2 buffer对象的长度

2.2.1 buffer.length属性
// =================================
const str = "hello world" // 当存储一个字符串
const arr = [1,2,3,44,44] // 存储一个数组

const buf1 = Buffer.from(str)
const buf2 = Buffer.from(arr)

console.log(buf1[0]); // 104
console.log(buf2[0]); // 1

console.log(str.length); // 11
console.log(buf1.length); // 11
console.log(arr.length); // 5
console.log(buf2.length); // 5

(1)Buffer中都是用二进制形式进行数据的存储,但在输出buffer时是以十六进制形式显示的,当存储的是string类型时,buf[index]输出的是字符对应的ascii码,当存储的是数组类型时,buf[index]输出的是对应数组元素的值
(2)buf.length和str.length虽然结果一样,但含义不一样,buf.length指的是占用内存的大小,也就是说占了11个字节空间,str.length指的是字符串长度,arr.length表示数组的长度

2.2.2 Buffer.byeLength(string[,encoding])
- 获取指定编码格式的字节长度
const str = '\u00bd + \u00bc = \u00be';

console.log(str); // ½ + ¼ = ¾ 
console.log(str.length); // 9 // 字符长度为9
console.log(Buffer.byteLength(str, 'utf8')); // utf8编码格式的字节长度为12

buffer一旦确定长度,就不能改变,并且buffer中的空间是连续的

2.3 比较buffer

2.3.1 Buffer.compare(buf1,buf2)

比较两个buffer实例的大小,比较规则:buf1大,返回1,buf1小,返回-1,相等,返回0

// 比较buffer的大小
const buf1 = Buffer.from('1234');
const buf2 = Buffer.from('0123');

let result = Buffer.compare(buf1,buf2) // buf1和buf2比较大小,buf1大,返回1
console.log(result); // 1
2.3.2 buf.compare(target)

比较两个buffer实例的大小,比较规则:buf1大,返回1,buf1小,返回-1,相等,返回0

const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
console.log(buf1.compare(buf1));
// Prints: 0
console.log(buf1.compare(buf2));
// Prints: -1

2.4 buffer的合并

Buffer.concat(list[, totalLength])

参数

  • list表示一个集合
  • totalLength表示list的长度
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.alloc(14);
const buf3 = Buffer.alloc(18);
const totalLength = buf1.length + buf2.length + buf3.length;

console.log(totalLength) // 42

const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
// 结果就是经过拼接后的buf1,buf2,buf3

2.5 判断某一个对象是否为buffer实例对象

Buffer.isBuffer(obj)
Buffer.isBuffer(Buffer.alloc(10)); // true
Buffer.isBuffer(Buffer.from('foo')); // true
Buffer.isBuffer('a string'); // false
Buffer.isBuffer([]); // false
Buffer.isBuffer(new Uint8Array(1024)); // false

2.6 给buffer数组排序

arr.sort(buf1,buf2,…)
const buf1 = Buffer.from('1234');
const buf2 = Buffer.from('0123');

const arr = [buf1,buf2]
console.log(arr.sort(Buffer.compare)); // 从小到大排序:[ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ]

2.7 判断buffer实例的起源

buffer.buffer属性
const arrayBuffer = new ArrayBuffer(16);
const buffer = Buffer.from(arrayBuffer);

console.log(buffer.buffer === arrayBuffer); // 判断buffer是不是起源于arrayBuffer对象

2.8 复制

buf.copy(target)

作用:复制一份buf到target中

const buf1 = Buffer.from('0123');
const buf2 = Buffer.alloc(10) // 创建一个10字节大小的buffer

console.log(buf1); // <Buffer 30 31 32 33>
console.log(buf2); // <Buffer 00 00 00 00 00 00 00 00 00 00>

buf1.copy(buf2) // 将buf1的数据复制到buf2中

console.log(buf1); // <Buffer 30 31 32 33>
console.log(buf2); // <Buffer 30 31 32 33 00 00 00 00 00 00>

2.9 迭代buffer实例中的所有索引和值

buf.entries()
const buf = Buffer.from('buffer');

for (const pair of buf.entries()) {
  console.log(pair);
}
// Prints:
//   [0, 98]
//   [1, 117]
//   [2, 102]
//   [3, 102]
//   [4, 101]
//   [5, 114]

2.10 比较两个buffer对象的字节是否一致

buffer.equals(otherBuffer)
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('ABC');
const buf3 = Buffer.from('ABCD');

console.log(buf1.equals(buf2));
// Prints: true
console.log(buf1.equals(buf3));
// Prints: false

2.11 用指定的值去取代/填充buffer中的值

buf.fill(value[, offset[, end]][, encoding])
const buf1 = Buffer.allocUnsafe(50).fill('h');
console.log(buf1.toString());
// Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
const buf2 = Buffer.alloc(10)
buf2.fill("a",1,5) // 用字符“a”填充下标1~5的元素
console.log(buf2); // <Buffer 00 61 61 61 61 00 00 00 00 00>

2.12 buf是否包含某一个指定值

buf.includes(value[, byteOffset][, encoding])
const buf = Buffer.from('this is a buffer');

console.log(buf.includes('this')); // 是否包含“this”字符串
// Prints: true

console.log(buf.includes(Buffer.from('a buffer'))); // 是否包含“a buffer”字符串
// Prints: true

console.log(buf.includes(97));
// Prints: true // 97是a的ascii码,所以也是true

console.log(buf.includes(Buffer.from('a buffer example')));
// Prints: false

console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
// Prints: true

console.log(buf.includes('this', 4));
// Prints: false

2.13 获取指定值出现在buf中的索引位置

buf.indexof(value)

作用:获取指定值第一次出现在buf中的索引位置

const buf = Buffer.from('this is a buffer');

console.log(buf.indexOf('this'));
// Prints: 0
console.log(buf.indexOf('is'));
// Prints: 2
console.log(buf.indexOf(Buffer.from('a buffer')));
// Prints: 8
console.log(buf.indexOf(97));
// Prints: 8 (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(Buffer.from('a buffer example')));
// Prints: -1
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
// Prints: 8
buf.lastIndexof()

获取指定值最后一次出现在buf中的索引位置

2.14 写入缓冲区

buf.write(string[, offset[, length]][, encoding])
  • string - 写入缓冲区的字符串。
  • offset - 缓冲区开始写入的索引值,默认为 0 。
  • length - 写入的字节数,默认为 buffer.length
  • encoding - 使用的编码。默认为 ‘utf8’ 。
  • 返回值:返回实际写入的大小。如果 buffer 空间不足, 则只会写入部分字符串
buf = Buffer.alloc(256);
len = buf.write("www.runoob.com"); // 14

console.log("写入字节数 : "+  len); // 

2.15 从缓冲区读取数据

buf.toString([encoding[, start[, end]]])
  • encoding - 使用的编码。默认为 ‘utf8’ 。
  • start - 指定开始读取的索引位置,默认为 0。
  • end - 结束位置,默认为缓冲区的末尾。
buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
  buf[i] = i + 97;
}

console.log( buf.toString('ascii'));       // 输出: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5));   //使用 'ascii' 编码, 并输出: abcde
console.log( buf.toString('utf8',0,5));    // 使用 'utf8' 编码, 并输出: abcde
console.log( buf.toString(undefined,0,5)); // 使用默认的 'utf8' 编码, 并输出: abcde

2.16 将Buffer转为JSON对象

buf.toJSON()

当字符串化一个 Buffer 实例时,JSON.stringify() 会隐式地调用该 toJSON()。

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);

// 输出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);

const copy = JSON.parse(json, (key, value) => {
  return value && value.type === 'Buffer' ?
    Buffer.from(value.data) :
    value;
});

// 输出: <Buffer 01 02 03 04 05>
console.log(copy);

2.17 缓冲区裁剪

buf.slice([start[, end]])

返回一个新的缓冲区,它和旧缓冲区指向同一块内存,但是从索引 start 到 end 的位置剪切。

var buffer1 = Buffer.from('runoob');
// 剪切缓冲区
var buffer2 = buffer1.slice(0,2);
console.log(buffer2.toString()); // ru

buffer中其他的方法可以参考nodejs官网

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值