什么是Buffer
- 缓冲区Buffer是暂时存放输入输出数据的一段内存。
- JS语言没有二进制数据类型,而在处理TCP和文件流的时候,必须要处理二进制数据。
- NodeJS提供了一个Buffer对象来提供对二进制数据的操作
- 是一个表示
固定内存分配
的全局对象,也就是说要放到缓存区中的字节数需要提前确定 - Buffer好比由一个8位字节元素组成的数组,可以有效的在JavasScript中表示二进制数据 Buffer 类被引入作为 Node.js API 的一部分,使其可以在 TCP 流或文件系统操作等场景中处理二进制数据流。
Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整。
Buffer 类在 Node.js 中是一个全局变量,因此无需使用 require('buffer').Buffer。
怎么创建buffer?
第一种方式:Buffer.alloc()
let buffer = Buffer.alloc(6);
//创建一个长度为6,并且用0填充的Buffer。
//这样申请方式,内存永远是干净的。
// 这种声明也比较耗时,因为声明之后,还要把里面的东西手动清空
//输出:<Buffer 00 00 00 00 00 00>
let buffer2 = Buffer.alloc(6,1);
// 创建一个长度为 6、且用 0x1 填充的 Buffer。
//输出:<Buffer 01 01 01 01 01 01>
第二种方式:Buffer.allocUnsafe()
let buffer = Buffer.allocUnsafe(6);
// 创建一个长度为 6、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快
//输出:<Buffer 07 00 00 00 00 00>
//但里面的东西是不安全的,可能含有旧数据。
//因此需要使用 fill() 或 write() 重写
buffer.fill(0);//对buffer进行重写
//输出:<Buffer 00 00 00 00 00 00>
定义buffer的3种方式
- 通过长度定义
// 创建一个长度为 10、且用 0 填充的 Buffer。
let buf1 = Buffer.alloc(10);
// 创建一个长度为 10、且用 0x1 填充的 Buffer。
let buf2 = Buffer.alloc(10, 1);
// 创建一个长度为 10、且未初始化的 Buffer。
let buf3 = Buffer.allocUnsafe(10);
- 通过字符串定义
let buf = Buffer.from('hello world');
//输出:<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
//默认是转成utf8格式的数据,也可以转成其他格式的数据,不支持gbk
3 通过数组定义
let buf = Buffer.from([1, 2, 3]);
// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
//<Buffer 01 02 03>
let buf2 = Buffer.from([16, 17, 18]);
//<Buffer 10 11 12>
//Buffer存的都是16进制,但是form存放的都是10进制,所以要除以16
以上3种方法,是创建buffer的3种方式
buf.write(string[, offset[, length]][, encoding])
- string 要写入 buf 的字符串。
- offset 开始写入 string 前要跳过的字节数。默认: 0。
- length 要写入的字节数。默认: buf.length - offset。
- encoding string 的字符编码。默认: 'utf8'。
- 返回: 写入的字节数。
操作内存空间
比如有个字符串'我爱编程',希望将我和爱编程分开输出,也就是第一次将我放到一个变量里,把剩余3个字放到一个变量里。 具体操作:
// 先申请一个Buffer
// 一个汉字3个字节,4个汉字12个字节
let buffer = Buffer.alloc(12);//里面是0填充的,内存是干净的
// 再构建两个buf1和buf2,然后把他们写到第一个个buffer里
let buf1 = '我';
let buf2 = '爱编程';
// write的参数分别是:写入的内容 ,偏移量,长度,编码格式
buffer.write(buf1,0,3,'utf8');//往buffer里面写内容buf1,从当前buffer的开头写,所以是第0个,长度是3,因为一个汉字3个字节
// 再写一个buf2
buffer.write(buf2,3,9,'utf8');
console.log(buffer);
//<Buffer e6 88 91 e7 88 b1 e7 bc 96 e7 a8 8b>
// 把buffer和字符串进行转换
console.log(buffer.toString());
//我爱编程
进制
- 0b 2进制
- 0x 16进制
- 0o 8进制
parseInt(): 将任意进制字符串
转换为十进制
parseInt("11", 2); // 3 2进制转10进制
parseInt("77", 8); // 63 8进制转10进制
parseInt("e7", 16); //175 16进制转10进制
toString(): 将10进制
转换为其它进制字符串
(3).toString(2)) // "11" 十进制转2进制
(17).toString(16) // "11" 十进制转16进制
(33).toString(32) // "11" 十提制转32进制
buffer其他常用的方法
buf.slice([start[, end]]);
start
: 新建的 Buffer 开始的位置。 默认: 0end
: 新建的 Buffer 结束的位置(不包含)。 默认: buf.length- 返回 :
<Buffer>
let buffer = Buffer.alloc(6);
let newBuffer = buffer.slice(0,3);
newBuffer[0] = 100;
console.log(buffer)
//<Buffer 64 00 00 00 00 00>
//由此可见,buffer里面存的是内存地址
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
target
<Buffer>
|<Uint8Array>
要拷贝进的 Buffer 或 Uint8Array。targetStart
target 中开始拷贝进的偏移量。 默认: 0sourceStart
buf 中开始拷贝的偏移量。 当 targetStart 为 undefined 时忽略。 默认: 0sourceEnd
buf 中结束拷贝的偏移量(不包含)。 当sourceStart
为undefined
时忽略。 默认: buf.length- 返回:
<integer>
被拷贝的字节数。
拷贝 buf 的一个区域的数据到 target 的一个区域,即便 target 的内存区域与 buf 的重叠。
let buffer = Buffer.alloc(6);
let buf1 = Buffer.from('一');
let buf2 = Buffer.from('万');
//要打印出万一
// 要把buf2 buf1的内容拷贝到buffer中
// write和copy的区别:write拷的是字符串,copy拷的是buffer
// 参数:目标 target中开始拷贝进的偏移量 buf1中开始拷贝的偏移量 buf1中结束拷贝的偏移量(不包含)
buf1.copy(buffer,3,0,3);//因为一时第二个文字,所以写在第3位(一个文字3个字节,第一个文字被占用,即012被占用)
buf2.copy(buffer,0,0,3);
console.log(buffer.toString())
//输出:万一
那么问题来了,如何实现copy方法? 首先,copy是Buffer实例上的方法,所以应该定义在Buffer原型上。
Buffer.prototype.mycopy = function(target, targetStart, sourceStart, sourceEnd){
/**
* 有4个参数
* 目标
* target中开始拷贝进的偏移量
* buf1中开始拷贝的偏移量
* buf1中结束拷贝的偏移量(不包含)
*
*/
//Buffer跟数组很像,有个迭代的功能
for(let i = sourceStart;i<sourceEnd; i++){//迭代每一项
// 从偏移量开始写
target[i+targetStart] = this[i]; //迭代每一项赋给目标buffer,this是buf1实例
}
}
buf1.mycopy(buffer,3,0,3);//因为一时第二个文字,所以写在第3位(一个文字3个字节,第一个文字被占用,即012被占用)
buf2.mycopy(buffer,0,0,3);
console.log(buffer.toString())
Buffer.concat(list[, totalLength])
list
< Array > 要合并的Buffer
或 Uint8Array 实例的数组totalLength
< integer > 合并时list
中Buffer
实例的总长度- 返回: < Buffer >
返回一个合并了 list 中所有 Buffer 实例的新建的 Buffer 。 如果 list 中没有元素、或 totalLength 为 0 ,则返回一个新建的长度为 0 的 Buffer 。 如果没有提供 totalLength ,则从 list 中的 Buffer 实例计算得到。 为了计算 totalLength 会导致需要执行额外的循环,所以提供明确的长度会运行更快。 如果提供了 totalLength,totalLength 必须是一个正整数。如果从 list 中计算得到的 Buffer 长度超过了 totalLength,则合并的结果将会被截断为 totalLength 的长度。
let buffer1 = Buffer.from('前');
let buffer2 = Buffer.from('端');
let buffer = Buffer.concat([buffer1,buffer2]).toString();//返回的是新Buffer,要toString()转译一下
console.log(buffer);
//输出:前端
let buf = Buffer.concat([buffer1,buffer2],10).toString();
console.log(buf);
//如果把长度写多了,会有问题,见下图
//多写的内容就是0

split
buf.indexOf(value[, byteOffset][, encoding])
value
< string > | < Buffer > | < Uint8Array > | < integer > 要搜索的值byteOffset
< integer > buf 中开始搜索的位置。默认: 0encoding
< string > 如果 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'- 返回: < integer > buf 中
value
首次出现的索引,如果 buf 没包含value
则返回 -1
如果 value
是:
- 字符串,则
value
根据 encoding 的字符编码进行解析。 Buffer
或Uint8Array
,则value
会被作为一个整体使用。如果要比较部分Buffer
,可使用 buf.slice()。- 数值, 则
value
会解析为一个 0 至 255 之间的无符号八位整数值。
const buf = Buffer.from('this is a buffer');
// 输出: 0
console.log(buf.indexOf('this'));
// 输出: 2
console.log(buf.indexOf('is'));
// 输出: 8
console.log(buf.indexOf(Buffer.from('a buffer')));
// 输出: 8
// (97 是 'a' 的十进制 ASCII 值)
console.log(buf.indexOf(97));
// 输出: -1
console.log(buf.indexOf(Buffer.from('a buffer example')));
// 输出: 8
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
// 输出: 4
console.log(utf16Buffer.indexOf('\u03a3', 0, 'ucs2'));
// 输出: 6
console.log(utf16Buffer.indexOf('\u03a3', -4, 'ucs2'));