一.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(buf1);
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')); //6
2.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的创建与填充可以在一行内完成
- 如果value中含有无效的字符,那么将会被截断;如果没有有效的数据,则不进行填充
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]]])
- target:目标buffer,即要执行复制替换的buffer
- targetStart:目标buffer的起始位置,标明从哪里开始替换,默认为0;
- sourceStart:源buffer的起始位置,标明从源buffer哪里进行复制,默认为0;
- sourceEnd:源buffer的结束位置(不包含),默认为buf.length
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
文章参考: