文章目录
- Buffer缓冲区
- 1、概述
- 2、Buffer对象API
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官网