buffer 缓冲区
基础
源代码:lib/buffer.js
作用:表示固定长度的字节序列,
- 是js中Uinit8Array类的子类
- 是直接处理二进制数据的全局类型
用法
-
引入
- es6
import Buffer from 'buffer'; - commonjs
const Buffer = require('buffer')
- es6
-
分配
-
v16
//创建长度为10字节的缓冲区 const buf1 = Buffer.alloc(10) //最大为 buffer.constants.MAX_LENGTH个字节 //这个会更快,但是可能有旧数据残留 const buf2 = Buffer.allocUnsafe(10); //是从预先分配的池子(大小Buffer.poolSize)中取的,一般4KB一下会取 //这个不会从池子里面取,会稍慢,用户保留一小块内存的情况 const buf3 = Buffer.allocUnsafeSlow(10); -
v15以前
const buf1 = new Buffer(10)
-
-
填充
- 公式
buf.fill(value[, offset[, end]][, encoding])
- 公式
-
分配+填充
-
v16
//创建10字节缓冲区,每个字节都用值1去填充 const buf4 = Buffer.alloc(10,1) //参数2不填则默认填充0 //原理:通过调用 buf.fill(fill) 进行初始化 //创建包含字节1、2、3的缓冲区 const buf5 = Buffer.from([1, 2, 3]); 这里面的每个元素,都要在0-255范围内 否则默认只取低八位 for (const b of buf5) { console.log(b); } // 打印: // 1 // 2 // 3 //创建包含字符串的UTF-8字节的缓冲区 const buf6 = Buffer.from('tést'); -
v15以前
const buf6 = new Buffer('tést')
-
-
指定字符编码
const buf7 = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); console.log(buf7); // 打印: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64> const buf8 = Buffer.from('hello world', 'utf8'); console.log(buf8.toString('hex')); // 打印: 68656c6c6f20776f726c64 console.log(buf8.toString('base64')); // 打印: aGVsbG8gd29ybGQ=将 Buffer 转换为 字符串 称为解码 将 字符串 转换为 Buffer 称为编码
-
Buffer.byteLength获取字符串占用字节const str = '\u00bd + \u00bc = \u00be'; console.log(`${str}: ${str.length} characters, ` + `${Buffer.byteLength(str, 'utf8')} bytes`); // 打印: ½ + ¼ = ¾: 9 characters, 12 bytes -
Buffer.compare多用于排序
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> ]
// (此结果相当于:[buf2, buf1]。)
-
Buffer.concat拼接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); //totalLength可省略,会自动算 console.log(bufA); // 打印: <Buffer 00 00 00 00 ...> console.log(bufA.length); // 打印: 42 -
Buffer.from全量复制const buf1 = Buffer.from('buffer'); const buf2 = Buffer.from(buf1); buf1[0] = 0x61; console.log(buf1.toString()); // 打印: auffer console.log(buf2.toString()); // 打印: buffer -
buf.copy部分复制- 复制到另一个buf
// 创建两个 `Buffer` 实例。 const buf1 = Buffer.allocUnsafe(26); const buf2 = Buffer.allocUnsafe(26).fill('!'); for (let i = 0; i < 26; i++) { // 97 是 'a' 的十进制 ASCII 值。 buf1[i] = i + 97; } // 将 `buf1` 字节 16 到 19 复制到 `buf2` 中,从 `buf2` 的字节 8 开始。 buf1.copy(buf2, 8, 16, 20); // 这相当于: // buf2.set(buf1.subarray(16, 20), 8); console.log(buf2.toString('ascii', 0, 25)); // 打印: !!!!!!!!qrst!!!!!!!!!!!!! - 复制到自己上面重叠区域
const buf = Buffer.allocUnsafe(26); for (let i = 0; i < 26; i++) { // 97 是 'a' 的十进制 ASCII 值。 buf[i] = i + 97; } buf.copy(buf, 0, 4, 10); console.log(buf.toString()); // 打印: efghijghijklmnopqrstuvwxyz
- 复制到另一个buf
-
判断
Buffer.isBuffer(obj)是否是buffer对象Buffer.isEncoding(encoding)内部是否支持此编码
-
常量
Buffer.poolSize默认为8192(字节)= 8KB
-
buf[i]通过索引访问和修改单个字节const str = 'Node.js'; const buf = Buffer.allocUnsafe(str.length); for (let i = 0; i < str.length; i++) { buf[i] = str.charCodeAt(i); } console.log(buf.toString('utf8')); // 打印: Node.js -
迭代器
buf.entries()const buf = Buffer.from('bu'); for (const pair of buf.entries()) { console.log(pair); } // 打印: // [0, 98] // [1, 117]buf.keys()buf.values()
-
buf.equals(otherBuffer)比较是否有相同字节 -
查找
buf.indexOf(value)返回出现的第一个索引位置buf.lastIndexOf(value)返回出现的最后第一个索引位置buf.includes(value)判断是否有
-
等价的两种方法——返回新Buffer
buf.slice(start[,end])- 返回新的Buffer,但是引用相同内存!!!
- 这跟Array对象里面的slice复制有差异!!!
- 如果要想复制,可以采用如下办法
const copiedBuf = Uint8Array.prototype.slice.call(buf);
buf.subarray(start[,end])- 这个跟上面slice一样,也是返回新的Buffer,引用相同内存
当TypedArray转化为Buffer时
import { Buffer } from 'buffer';
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// 复制 `arr` 的内容。
const buf1 = Buffer.from(arr);
// 与 `arr` 共享内存。
const buf2 = Buffer.from(arr.buffer);
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer 88 13 a0 0f>
arr[1] = 6000;
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer 88 13 70 17>
arr[1] = 3000;
console.log(buf1);
// 打印: <Buffer 88 a0>
console.log(buf2);
// 打印: <Buffer b8 0b 70 17>
buffer.
分析可见
- 复制arr的内容,根本得不到真正的数据
- 要使用arr.buffer才能得到,但代价就是需要共享内存
可以只取一部分变成buffer 方法:指定偏移量和截取长度
import { Buffer } from 'buffer';
const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
//从0号开始,截取16个
console.log(buf.length);
// 打印: 16
当Buffer转化为TypedArray时
import { Buffer } from 'buffer';
const buf = Buffer.from([1, 2, 3, 4]);
//以buf为参数
const uint32array = new Uint32Array(buf);
console.log(uint32array);
// 打印: Uint32Array(4) [ 1, 2, 3, 4 ]
//以buf.buffer为参数
const uint16array = new Uint16Array(
buf.buffer,
buf.byteOffset,
buf.length / Uint16Array.BYTES_PER_ELEMENT
);
console.log(uint16array);
// 打印: Uint16Array(2) [ 513, 1027 ]
分析可见
- 以buf为参数,会把每个元素解释为整型,赋予数组
- 以buf.buffer为参数,单个元素占16位时,由于共享内存,所以直接合并两个字节,解释为单个数组元素
15.7版本新增Bolb类(目前仍是实验性功能)
作用:封装了不可变的原始数据,可在多个工作线程之间安全地共享
import { Blob } from 'buffer';
const blob = new Blob(['hello there']);
blob.text().then(console.log);
//打印:hello there
配套有MessagePort类,可以发送多个目的地
好处:无需立即复制数据,只有在调用 arrayBuffer() 或 text() 方法时才会复制
const mc1 = new MessageChannel();
mc1.port1.onmessage = async ({ data }) => {
console.log(await data.arrayBuffer());
mc1.port1.close();
};
mc1.port2.postMessage(blob);
//可以新建多个MessageChannel