node学习笔记-buffer

一.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'));  //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

文章参考:   

    - node官网buffer

阅读更多

没有更多推荐了,返回首页