二进制数据-buffer
// 模块概览
// Buffer是node的核心模块,开发者利用他来处理二进制数据,比如文件流的读写,网络请求数据的处理
// Buffer的API很多,仅挑选常用的API来进行讲解
创建
new Buffer(array);
Buffer.alloc(length);
Buffer.allocUnsafe(length);
Buffer.from(array);
new Buffer(array)
const buf = new Buffer([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
const array = "buffer".split("").map((v) => {
return "0x" + v.charCodeAt(0).toString(16);
});
console.log(array.join()); // 0x62,0x75,0x66,0x66,0x65,0x72
Buffer.alloc(length) 创建一个指定大小的 buffer
const buf1 = Buffer.alloc(10); //长度未10的buffer 初始值为 0x0
console.log(buf1); // <Buffer 00 00 00 00 00 00 00 00 00 00>
const buf2 = Buffer.alloc(10, 1); // 长度未10的buffer 初始值为0x1
console.log(buf2); // <Buffer 01 01 01 01 01 01 01 01 01 01>
const buf3 = Buffer.allocUnsafe(10); // 长度为10的buffer,初始值不确定
console.log(buf3); // <Buffer 00 00 00 00 00 00 00 00 00 00>
const buf4 = Buffer.from([1, 2, 3]); // 长度为3的buffer,初始值为 0x01, 0x02, 0x03
console.log(buf4); // <Buffer 01 02 03>
Buffer.from() 从字符串或者数组创建一个 buffer
Buffer.from(array)
// [0x62, 0x75, 0x66, 0x66, 0x65, 0x72] 为字符串 "buffer"
// 0x62 为16进制,转为十进制就是98,代表的字母就是b
const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
console.log(buf.toString()); // buffer
Buffer.from(string, encoding)
const buf = Buffer.from("this is a tést"); //默认采用utf8
console.log(buf.toString()); // this is a tést 因为编码为utf8 所以可以正常打印
console.log(buf.toString("ascii")); // this is a tC)st 转换为字符串时候,编码不是utf8 所以乱码
// 对乱码的分析
const letter = "é";
const buff = Buffer.from(letter); // 默认编码是utf8 这里占据了两个字节 <Buffer c3 a9>
const len = buff.length; // 2
const code = buff[0]; // 第一个字节是 0xc3 即195 超出ascii的最大支持范围
const binary = code.toString(2); // 192的二进制 10101001
const finalBinary = binary.slice(1); // 将高位的1舍弃,变成0101001
const finalCode = parseInt(finalBinary, 2); // 0101001 对应的十进制 67
const finalLetter = String.fromCharCode(finalCode); // 67 对应的字符为 C
console.log(finalLetter); // C
Buffer.from(buffer)
// 创建buffer实例,并将buffer的数据拷贝到新的实例字中去.
const buff = Buffer.from("buffer");
const buff2 = Buffer.from(buff);
console.log(buff.toString()); // buffer
console.log(buff2.toString()); // buffer
buff2[0] = 0x61;
console.log(buff.toString()); // buffer
console.log(buff2.toString()); // auffer
buffer 比较
buf.equals(otherBuffer)
// 判断两个buffer实例存储的数据是否相同,如果是返回true,否则返回false
// 例子1 编码一样 内容相同
const buf1 = Buffer.from("A");
const buf2 = Buffer.from("A");
console.log(buf1.equals(buf2)); // true
// 例子2 编码一样 内容不容
const buf3 = Buffer.from("A");
const buf4 = Buffer.from("B");
console.log(buf3.equals(buf4)); // false
// 例子3 编码不一样 内容一样
const buf5 = Buffer.from("ABC"); // <Buffer 41 42 43>
const buf6 = Buffer.from("414243", "hex");
console.log(buf5.equals(buf6)); // true
// 只要比较的两者内容相同,buf1.equals(buf2) 就返回true
buf.compare(target, targetStart, targetEnd, sourceStart, sourceEnd)
// 同样是对比两个buffer实例进行比较,不同的是
// 1.可以指定特定的范围(通过start end 指定)
// 2.返回值为整数,达标buf target的大小关系
// 假设返回值为
// 0 buf target 大小相同
// 1 buf 大于 target 也就是说buf应该排在target的后面
// 2 buf 小于 target 也就是说buf应该排在target的前面
const buf1 = Buffer.from("ABC");
const buf2 = Buffer.from("BCD");
const buf3 = Buffer.from("ABCD");
console.log(buf1.compare(buf1)); // 0
console.log(buf1.compare(buf2)); // -1
console.log(buf1.compare(buf3)); // -1
console.log(buf2.compare(buf1)); // 1
console.log(buf2.compare(buf3)); // 1
console.log([buf1, buf2, buf3].sort(Buffer.compare)); // [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
Buffer.compare(buf1, buf2)
// 跟 buf.compare(target) 大同小异,一般用于排序
const buf1 = Buffer.from("3124");
const buf2 = Buffer.from("0123");
const arr = [buf1, buf2];
console.log(arr.sort(Buffer.compare)); // [ <Buffer 30 31 32 33>, <Buffer 33 31 32 34> ]
Buffer.from(Array)
// 这里稍微研究下 Buffer.from(Array) 下面是官网文档对弈API的说明,也就是说,每个array的元素对应一个字节,取值从0到255
数组元素为数字
const buf = Buffer.from([62]);
console.log(buf); // <Buffer 3e>
console.log(buf[0] === parseInt("3e", 16)); // true
console.log(buf[0] === 62); // true
const buf1 = Buffer.from([062]);
console.log(buf1); // <Buffer 3e>
console.log(buf1[0] === 50); // true
console.log(buf1[0] === parseInt(62, 8)); // true
console.log(buf1[0] === parseInt(32, 16)); // true
const buf2 = Buffer.from([0x62]); // <Buffer 62>
console.log(buf2);
console.log(buf2[0] === 98); // true
console.log(buf2[0] === parseInt(62, 16)); // true
数组元素为字符串
// 传入元素为字符串的场景
// 1. 0 开头的字符串,在 parseInt('062')时可以解释为62,也可以解释为50(八进制),这里看到采用第一种解释
// 2. 字符串场景, 跟 parseInt() 有没有关系,暂时不深入了解
const buff = Buffer.from(["62"]);
console.log(buff); // <Buffer 3e>
console.log(buff[0] === parseInt("3e", 16)); // true
console.log(buff[0] === parseInt("62")); // true
const buff2 = Buffer.from(["062"]);
console.log(buff2); // <Buffer 3e>
console.log(buff2[0] === parseInt("3e", 16)); // true
console.log(buff[0] === parseInt("62")); // true
const buff3 = Buffer.from(["0x62"]);
console.log(buff3); //<Buffer 62>
console.log(buff3[0] === parseInt("62", 16)); // true
console.log(buff3[0] === parseInt("0x62")); // true
数组元素大小超出一个字节
const buff = Buffer.from([256]);
console.log(buff); // <Buffer 00>
Buffer.from('1')
// 将 Buffer.from('1')[0] 跟 1 划等号, 其实1对应的编码是49
const buff = Buffer.from("1");
console.log(buff); // <Buffer 31>
console.log(buff[0] === 1); // false
// 对比后发现,编码为1的是个控制字符, 标识 Start of Heading
console.log(String.fromCharCode(49)); // 1
console.log(String.fromCharCode(1)); // '\u0001'
Buffer.concat()
buffer 连接: Buffer.concat(list, totalLength)
// 个人感觉 totalLength 参数很多余,从官方文档上看,是处于性能提升的角度考虑,不过内部实现也只是遍历了list,将length累加得到totalLength,从这点来看,性能优化是几乎可以忽略不计的
const buff1 = Buffer.alloc(10);
const buff2 = Buffer.alloc(20);
const totalLength = buff1.length + buff2.length;
console.log(totalLength); // 30
const buff3 = Buffer.concat([buff1, buff2], totalLength);
console.log(buff3.length); // 30
// 除了上面提到的优化,totalLength还有两点需要注意,假设list里面所有的buffer长度累加和为length
// 1. totalLength>length 返回长度未totalLength的Buffer实例,超出长度的部分填充为0
// 2. totalLength<length 返回长度未 totalLength 的buffer实例,后面部分舍弃
const buff4 = Buffer.from([1, 2]);
const buff5 = Buffer.from([3, 4]);
const buff6 = Buffer.concat([buff4, buff5], 5);
console.log(buff6); // <Buffer 01 02 03 04 00>
console.log(buff6.length); // 5
const buff7 = Buffer.concat([buff4, buff5], 3);
console.log(buff7); // <Buffer 01 02 03>
console.log(buff7.length); // 3
Buffer.copy()
Buffer.copy(target, targetStart, sourceStart, sourceEnd) 拷贝
// 使用比较简单,如果忽略后面的三个参数,那么就是将buf的数据拷贝到target里去,
const buff1 = Buffer.from([1, 2]);
const buff2 = Buffer.alloc(2);
console.log(buff1); // <Buffer 01 02>
console.log(buff2); // <Buffer 00 00>
buff1.copy(buff2);
console.log(buff2); // <Buffer 01 02>
// 另外三个参数
let buff3 = Buffer.allocUnsafe(26);
let buff4 = Buffer.allocUnsafe(26).fill("!");
for (let index = 0; index < 26; index++) {
buff3[index] = index + 97;
}
console.log(buff3); // <Buffer 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a>
buff3.copy(buff4, 8, 16, 20);
console.log(buff4); // <Buffer 21 21 21 21 21 21 21 21 71 72 73 74 21 21 21 21 21 21 21 21 21 21 21 21 21 21>
console.log(buff4.toString("ascii", 0, 25)); // !!!!!!!!qrst!!!!!!!!!!!!!
buffer.indexOf()
buffer.indexOf(value, byteOffset, encoding) 查找
// 跟数组的查找差不多,需要注意的是, value可能是String Buffer Integer
// string 如果是字符串,那么encoding就是器对应的编码,默认是utf-8
// Buffer 如果是buffer实例,那么会将value中的完整数据跟buf进行对比
// Integer 如果是数字,那么value会被当做无符号的8位整数,取值范围是0到255
const buf = Buffer.from("this is a buffer");
console.log(buf.indexOf("this")); // 0
console.log(buf.indexOf("is")); // 2
console.log(buf.indexOf(Buffer.from("a buffer"))); // 8
console.log(buf.indexOf(97)); // 8
console.log(buf.indexOf(Buffer.from("a buffer example"))); // -1
console.log(Buffer.from("a buffer example").slice(0, 8)); // <Buffer 61 20 62 75 66 66 65 72> 等于 a buffer
console.log(buf.indexOf(Buffer.from("a buffer example").slice(0, 8))); // 8
const utf16Buffer = Buffer.from("\u039a\u0391\u03a3\u03a3\u0395", "ucs2");
console.log(utf16Buffer); // <Buffer 9a 03 91 03 a3 03 a3 03 95 03>
console.log(utf16Buffer.indexOf("\u03a3", 0, "ucs-2")); // 4
console.log(utf16Buffer.indexOf("\u03a3", -4, "ucs-2")); // 6
buf.write()
buf.write(string,offset,length,encoding)
// 将string写入buf实例,同时返回写入的字节数
// 参数如下
// 1. string 写入的字符串
// 2. offset 从buf的第几位开始写入,默认是0
// 3. length 写入多少个字节,默认是buf.length - offset
// 4. encoding 字符串的编码,默认是utf-8
const buff = Buffer.alloc(4);
console.log(buff); // <Buffer 00 00 00 00>
buff.write("ab");
console.log(buff); // <Buffer 61 62 00 00>
buf.fill()
// 用value来填充buf,常用于初始化buf,参数如下
// 1. value 同来填充的内容,可以是 Buffer String, Integer
// 2. offset 从第几位开始填充,默认是0
// 3. end 停止填充的位置 默认是 buf.length
// 4. encoding 如果value是string 那么value 的编码默认为utf-8
const buff = Buffer.alloc(20).fill("a");
console.log(buff.toString()); // aaaaaaaaaaaaaaaaaaaa
const buff1 = Buffer.alloc(20).fill("a", 10);
console.log(buff1.toString()); // aaaaaaaaaa
const buff2 = Buffer.alloc(20).fill("a", 10, 15);
console.log(buff2.toString()); // aaaaa
buf.toString()
buf.toString
const buff = Buffer.from("hello");
console.log(buff.toString()); // hello
console.log(buff.toString("utf-8", 1)); // ello
console.log(buff.toString("utf-8", 1, 2)); // e
buf.toJSON()
buf.toJSON() 转成 json 字符串
const buff = Buffer.from("hello");
console.log(buff.toJSON()); // { type: 'Buffer', data: [ 104, 101, 108, 108, 111 ] }
buf.values(), buf.keys(), buf.entries()
buf.values(), buf.keys(), buf.entries() 遍历
// 用于对buf进行 for of 的遍历
const buff = Buffer.from("abcde");
for (const key of buff.keys()) {
console.log("key is", key);
// key is 0
// key is 1
// key is 2
// key is 3
// key is 4
}
for (const value of buff.values()) {
console.log("value is", value);
// value is 97
// value is 98
// value is 99
// value is 100
// value is 101
}
for (const pair of buff.entries()) {
console.log("pair is", pair, pair[0], pair[1]);
// pair is [ 0, 97 ] 0 97
// pair is [ 1, 98 ] 1 98
// pair is [ 2, 99 ] 2 99
// pair is [ 3, 100 ] 3 100
// pair is [ 4, 101 ] 4 101
}
buf.slice()
buf.slice(start, end) 截取
// 用于截取buf,并返回一个新的buffer实例,需要注意的是,这里返回的buffer实例指向仍然是buf的内存地址,所以对新的buffer实例的修改会影响到buf
let buff1 = Buffer.from("abcde");
console.log(buff1); // <Buffer 61 62 63 64 65>
let buff2 = buff1.slice();
console.log(buff2); // <Buffer 61 62 63 64 65>
let buff3 = buff1.slice(1, 3);
console.log(buff3); // <Buffer 62 63>
console.log(buff1); // <Buffer 61 62 63 64 65>
buff3[0] = 97;
console.log(buff1); // <Buffer 61 61 63 64 65>
TODO
// 1. 创建、拷贝、截取、转换、查找
// 2. buffer、arraybuffer、dataview、typedarray
// 3. buffer vs 编码
// 4. Buffer.from()、Buffer.alloc()、Buffer.alocUnsafe()
// 5. Buffer vs TypedArray