Buffer(缓冲器)

什么是Buffer

  • 缓冲区Buffer是暂时存放输入输出数据的一段内存。
  • JS语言没有二进制数据类型,而在处理TCP和文件流的时候,必需要处理二进制数据。
  • NodeJS提供了一个Buffer对象来提供对二进制数据的操做
  • 是一个表示固定内存分配的全局对象,也就是说要放到缓存区中的字节数须要提早肯定
  • Buffer比如由一个8位字节元素组成的数组,能够有效的在JavasScript中表示二进制数据 Buffer 类被引入做为 Node.js API 的一部分,使其能够在 TCP 流或文件系统操做等场景中处理二进制数据流。

Buffer 类的实例相似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被建立时肯定,且没法调整。javascript

Buffer 类在 Node.js 中是一个全局变量,所以无需使用 require('buffer').Buffer。前端

怎么建立buffer? 第一种方式:Buffer.alloc()java

let buffer = Buffer.alloc(6);
 //建立一个长度为6,而且用0填充的Buffer。
 //这样申请方式,内存永远是干净的。
 // 这种声明也比较耗时,由于声明以后,还要把里面的东西手动清空
 //输出:<Buffer 00 00 00 00 00 00>
 
 let buffer2 = Buffer.alloc(6,1);
 // 建立一个长度为 六、且用 0x1 填充的 Buffer。 
 //输出:<Buffer 01 01 01 01 01 01>
复制代码

第二种方式:Buffer.allocUnsafe()编程

let buffer = Buffer.allocUnsafe(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种方式

  1. 经过长度定义
// 建立一个长度为 十、且用 0 填充的 Buffer。
let buf1 = Buffer.alloc(10);
// 建立一个长度为 十、且用 0x1 填充的 Buffer。
let buf2 = Buffer.alloc(10, 1);
// 建立一个长度为 十、且未初始化的 Buffer。
let buf3 = Buffer.allocUnsafe(10);
复制代码
  1. 经过字符串定义
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个字放到一个变量里。 具体操做:ui

// 先申请一个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]]);this

  • start : 新建的 Buffer 开始的位置。 默认: 0
  • end : 新建的 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 中开始拷贝进的偏移量。 默认: 0
  • sourceStart buf 中开始拷贝的偏移量。 当 targetStart 为 undefined 时忽略。 默认: 0
  • sourceEnd buf 中结束拷贝的偏移量(不包含)。 当 sourceStartundefined 时忽略。 默认: 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 > 合并时 listBuffer 实例的总长度
  • 返回: < 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 中开始搜索的位置。默认: 0
  • encoding < string > 若是 value 是一个字符串,则这是它的字符编码。 默认: 'utf8'
  • 返回: < integer > buf 中 value 首次出现的索引,若是 buf 没包含 value 则返回 -1

若是 value 是:

  • 字符串,则 value 根据 encoding 的字符编码进行解析。
  • BufferUint8Array,则 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'));
复制代码