一.Buffer创建
1. buffer.alloc(size[, fill[, encoding]])
- size:新建的Buffer期望的长度
- fill:用来填充新建的buffer;默认0
- encoding:如果fill为字符串,那么encoding是它的编码;默认'utf8'
2. Buffer.allocUnsafe(size)
- size:新建的Buffer期望的长度
3. Buffer.allocUnsafeSllow(size)
- size:新建的Buffer期望的长度
注:在以上的创建方式中,如下会出现报错:
- size值大于buffer.constants.MAX_LENGTH或小于 0,会抛出RangeError错误
- size不是一个数值,会抛出TypeError错误
4. Buffer.from()
// buffer.from(array); -> 如果array不是一个数组,则抛出TypeError的错误
console.log(Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x11]));
// buffer.from(string[,encoding]); -> 如果string不是一个字符串,则抛出TypeError的错误
let buf1 = Buffer.from('this is a test','utf8');
console.log(buf1);
console.log(buf1.toString());
// buffer.from(buffer); -> 如果buffer不是一个Bufer,则抛出TypeError的错误
let buf2 = Buffer.from('buffer');
console.log(buf2);
console.log(Buffer.from(buf2));
二.是什么令Buffer.allocUnsafe和Buffer.allocUnsafeSlow()不安全
当调用 Buffer.allocUnsafe()
和 Buffer.allocUnsafeSlow()
时,被分配的内存段是未初始化的(没有用 0 填充)。 虽然这样的设计使得内存的分配非常快,但已分配的内存段可能包含潜在的敏感旧数据。 使用通过 Buffer.allocUnsafe()
创建的没有被完全重写内存的Buffer ,在Buffer内存可读的情况下,可能泄露它的旧数据。
Buffer.allocUnsafe()
有明显的性能优势,但必须额外小心,以避免给应用程序引入安全漏洞。
三.类方法
1. Buffer.byteLength(string[, encoding])
- 返回字符串的实际字节长度,注:并非字符串的字符长度
- string:要计算的长度的值;
- 如果string为字符串,那么这个是它的编码值;默认'utf8'
var str = '北京'; console.log(str.length); //2 console.log(Buffer.from(str)); //<Buffer e5 8c 97 e4 ba ac> console.log(Buffer.byteLength(str,'utf8')); //62.Buffer.compare(buf1,buf2)
- 对buf1和buf2进行比较,通常用于数组的排序
const buf1 = Buffer.from('0123'); const buf2 = Buffer.from('1234'); const arr = [buf1,buf2]; // [ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ] // 该方法相当于调用buf1.compare(buf2) console.log(Buffer.compare(buf1,buf2)); //-1 console.log(buf1.compare(buf2)); //-1 // 当buf1 与 buf2 相同时,返回0 // 当buf2 排在 buf1 后面时,返回-1 // 当buf2 排在 buf1 前面时,返回1 // 用与数组的排序 console.log(arr.sort(Buffer.compare)); //[ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ]
3.Buffer,concat(list[, totalLength])
- 用于返回合并所有list中所有Buffer实例新建的Buffer;
- list:要合并的buffer或Uint8Array实例数组;
- totalLength:合并list中Buffer的总长度;
注意:
- 当list中没有元素时或totalLength为0时,返回一个新建长度为0的Buffer
- 如果没有指定totalLength,会从list中Buffer实例计算得到, 为了计算totalLength会导致需要执行额外的循环,所以提供明确的长度会运行更快
- 如果提供了totalLength,totalLength必须是一个正整数
- 如果从list中计算得到的Buffer长度超过了totalLength,则合并的结果将会被截断为totalLength的长度
- 如果从list中计算得到的Buffer长度小于totalLength,则剩余的长度会以0填充
以下是concat原理:
let buf1 = Buffer.from('文字1'); let buf2 = Buffer.from('文字2'); Buffer.MyConcat = function(list, length) { // 判断list是否为一个数组 if (!Array.isArray(list)){ throw new TypeError('list" argument must be an Array of Buffer or Uint8Array instances'); } // 如果数组为0,那么返回一个字节为0的buffer if (list.length === 0) return Buffer.alloc(0); if (length === undefined) { // 如果长度未定义,那么根据list计算长度,否则就取给定长度 length = 0; for (i = 0; i < list.length; i++) length += list[i].length; } else { length = length >>> 0; } // 创建字节长度为length的buffer var buffer = Buffer.allocUnsafe(length); // 进行拼接 var pos = 0; for (i = 0; i < list.length; i++) { var buf = list[i]; buf.copy(buffer, pos); pos += buf.length; } // 如果给定长度大于list的长度,那么剩余补0 if (pos < length){ buffer.fill(0,pos,length) } return buffer; }; console.log(Buffer.MyConcat([buf1,buf2],20));//<Buffer e6 96 87 e5 ad 97 31 e6 96 87 e5 ad 97 32 00 00 00 00 00 00> console.log(Buffer.concat([buf1,buf2],20));//<Buffer e6 96 87 e5 ad 97 31 e6 96 87 e5 ad 97 32 00 00 00 00 00 00> console.log(Buffer.MyConcat([buf1,buf2],7));//<Buffer e6 96 87 e5 ad 97 31> console.log(Buffer.concat([buf1,buf2],7));//<Buffer e6 96 87 e5 ad 97 31> console.log(Buffer.MyConcat([buf1,buf2]));//<Buffer e6 96 87 e5 ad 97 31 e6 96 87 e5 ad 97 32> console.log(Buffer.concat([buf1,buf2]));//<Buffer e6 96 87 e5 ad 97 31 e6 96 87 e5 ad 97 32>
4.Buffer.isBuffer(obj)
- 用于判断obj是否是一个buffer
let buf1 = Buffer.from('str'); console.log(Buffer.isBuffer(buf1)); //true
5.Buffer.poolSize
- 这是用于决定预分配的、内部 Buffer
实例池的大小的字节数,默认为8192,即8KB
三.Buffer常用方法:
1.buf.slice([start[,end])
- 用于对buffer的截取;
- start:新建的buffer开始的位置;
- end:新建的buffer结束的位置(不包含),默认为buf.length;
注:
- 这里的slice为浅拷贝
- 深拷贝:就是两个一样的东西,但没有关系,即指向不同的内存空间
- 浅拷贝:两个对象存放的空间是一样的
let buf1 = Buffer.from('test'); console.log(buf1); //<Buffer 74 65 73 74> let buf2 = buf1.slice(1,3); console.log(buf2); //<Buffer 65 73> buf2[0] = 97; console.log(buf2); //<Buffer 61 73> console.log(buf2.toString()); //as console.log(buf1.toString()); //tast 可以发现我们改变了buf2的值后,buf1的值也会随之改变
以下为slice的源码分析:
Buffer.prototype.slice = function slice(start, end) { const srcLength = this.length; // 获取要截取buffer的长度 start = adjustOffset(start, srcLength); // 对start进行校正 // 对end进行校正,如果没有传,那么返回原buffer的长度 end = end !== undefined ? adjustOffset(end, srcLength) : srcLength; const newLength = end > start ? end - start : 0; // 获取新的buffer的长度 return new FastBuffer(this.buffer, this.byteOffset + start, newLength); // 返回截取的buffer }; function adjustOffset(offset, length) { // 获取一个整数值 offset = Math.trunc(offset); // 如果传入的值为0或经过Math.trunc后不为数字类型,那么返回0 if (offset === 0 || offset !== offset) { return 0; } else if (offset < 0) { // 如果得到的值为负数,那么将offset与length长度相加,如果还小于0,返回0 offset += length; return offset > 0 ? offset : 0; } else { // 如果得到的offset小于length,返回offset,否则返回length return offset < length ? offset : length; } }
2.buf.toString([encoding[,start[,end]]])
- 用于将buf根据encoding指定的编码解码buf为一个字符串
- encoding:解码使用的字符编码,默认'utf8';
- start:开始解码的字符偏移量,默认为0;
- end:解码结束的字符偏移量(不包含),默认为buf.length;
let buf1 = Buffer.from('test'); console.log(buf1.toString('utf8')); // test console.log(buf1.toString(undefined, 0, 3)); //tes console.log(buf1.toString('base64',0,3)); // dGVzdA== 经过base64解码为test以下是可用的解码方式:
// 以下encoding是可用的就解码方式 function stringSlice(buf, encoding, start, end) { if (encoding === undefined) return buf.utf8Slice(start, end); encoding += ''; switch (encoding.length) { case 4: if (encoding === 'utf8') return buf.utf8Slice(start, end); if (encoding === 'ucs2') return buf.ucs2Slice(start, end); encoding = encoding.toLowerCase(); if (encoding === 'utf8') return buf.utf8Slice(start, end); if (encoding === 'ucs2') return buf.ucs2Slice(start, end); break; case 5: if (encoding === 'utf-8') return buf.utf8Slice(start, end); if (encoding === 'ascii') return buf.asciiSlice(start, end); if (encoding === 'ucs-2') return buf.ucs2Slice(start, end); encoding = encoding.toLowerCase(); if (encoding === 'utf-8') return buf.utf8Slice(start, end); if (encoding === 'ascii') return buf.asciiSlice(start, end); if (encoding === 'ucs-2') return buf.ucs2Slice(start, end); break; case 6: if (encoding === 'latin1' || encoding === 'binary') return buf.latin1Slice(start, end); if (encoding === 'base64') return buf.base64Slice(start, end); encoding = encoding.toLowerCase(); if (encoding === 'latin1' || encoding === 'binary') return buf.latin1Slice(start, end); if (encoding === 'base64') return buf.base64Slice(start, end); break; case 3: if (encoding === 'hex' || encoding.toLowerCase() === 'hex') return buf.hexSlice(start, end); break; case 7: if (encoding === 'utf16le' || encoding.toLowerCase() === 'utf16le') return buf.ucs2Slice(start, end); break; case 8: if (encoding === 'utf-16le' || encoding.toLowerCase() === 'utf-16le') return buf.ucs2Slice(start, end); break; } throw new TypeError('Unknown encoding: ' + encoding); }
3.buf.fill(value[, offset[, end]][, encoding])
- value:用来填充buf的值;
- offset:开始填充buf前要跳过的字节数,默认为0;
- end:结束填充buf的位置(不包含),默认为buf.length;
- encoding:如果value是一个字符串,那么这个是它的字符编码,默认'utf8';
注:
- 如果未指定offset和end,则填充整个buf。 这个简化使得一个Buffer的创建与填充可以在一行内完成
let buf1 = Buffer.allocUnsafe(5); console.log(buf1); //<Buffer 06 00 00 00 00> console.log(buf1.fill('aazz', 'hex')); // <Buffer aa aa aa aa aa> z为非有效十六进制,则只填充aa,从z截断 let buf2 = Buffer.allocUnsafe(5); console.log(buf2); // <Buffer 28 70 c0 ea a1> console.log(buf2.fill('zz', 'hex')); // <Buffer 28 70 c0 ea a1> z为非有效十六进制,不进行填充
4.buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
let buf1 = Buffer.allocUnsafe(26); let buf2 = Buffer.allocUnsafe(26).fill('0'); for (let i = 0; i < 26; i++) { // 97 是 'a' 的十进制 ASCII 值 buf1[i] = i + 97; } console.log(buf1.toString());// abcdefghijklmnopqrstuvwxyz console.log(buf2.toString());// 00000000000000000000000000 buf1.copy(buf2, 8, 16, 20); console.log(buf2.toString()); // 00000000qrst00000000000000
文章参考: