Skip to content

Buffer

Buffer 用来表示 Node 中的二进制,表现出来的是 16 进制,代表的是内存,不能随便调整大小。

js
const b1 = Buffer.alloc(10) // Node 中的最小单位是字节
const b1 = Buffer.allocUnsafe(10) // 从内存中拿 10 个字节,不一定都是 0。
const b2 = Buffer.from([1, 2, 10, 22, 256]) // 超过 255 会取余
const b3 = Buffer.from('一') // 一个汉字三个字节
console.log(b1.length) // 字节长度,长度不能改变。

Buffer 可以和字符串互相转化

js
Buffer.from('foo').toString('base64') // 转化成 base64 格式

// 解决 Buffer 不支持的编码,如 GBK
const iconvLite = require('iconv-lite')
const buffer = fs.readFileSync(path.resolve(__dirname, 'gbk.txt')) // 二进制
buffer.toString('gbk') // 报错
buffer.toString() // 乱码
iconvLite.decode(content, 'gbk') // 二进制转 GBK

Buffer.prototype.copy

js
const b1 = Buffer.from('foo')
const b2 = Buffer.from('bar')

// 声明一个更大的 Buffer,将多个 Buffer 拷贝上去。
const b3 = Buffer.alloc(6)
b1.copy(b3, 0, 0, 3) // 数字分别表示拷贝到新 Buffer 的位置,源的开始和结束。
b2.copy(b3, 3, 0, 3)

// 不会影响新的 Buffer,因为是两块内存。
b1[0] = 10

console.log(b3.toString()) // foobar

Buffer.prorotype.copy = function (
  targetBuffer, 
  targetStart, 
  sourceStart = 0, 
  sourceEnd = this.length
) {
  for (let i = sourceStart; i < sourceEnd; i++) {
    targetBuffer[targetStart++] = this[i]
  }
}

Buffer.prototype.slice

js
const b1 = Buffer.from('foo')
console.log(b1.slice(1).toString()) // oo

Buffer.prototype.indexOf

第一次出现在第几个字节

js
const buffer = Buffer.from('foofoo')
const index1 = buffer.indexOf('f') 
const index2 = buffer.indexOf('f', 2) // 从第 2 个字节开始找
console.log(index1, index2) // 0 3

实现 Buffer.prototype.split

js
Buffer.prototype.split = function (s) {
  const buffer = this
  const res = []
  const length = Buffer.from(s).length
  let prevIndex = 0
  let currentIndex = buffer.indexOf(s)

  if (currentIndex === -1) {
    res.push(buffer)

    return res
  }

  // foofoo
  while (currentIndex !== -1) {
    const token = buffer.slice(prevIndex, currentIndex)

    if (token.length) {
      res.push(token)
    }

    prevIndex = currentIndex + length
    currentIndex = buffer.indexOf(s, prevIndex)
  }

  if (prevIndex < buffer.length) {
    res.push(buffer.slice(prevIndex))
  }

  return res
}

const buffer = Buffer.from('foofoo')
const segments = buffer.split('of')
console.log(segments)

Buffer.slice

js
const b1 = Buffer.from('foo')
const sliced = b1.slice(0, 1) // 从内存地址中截取,会对源 Buffer 也造成影响。
sliced[0] = 10 
console.log(b1.toString()) // oo

const ary = [[1, 2, 3], [4, 5, 6]]
const slicedAry = ary.slice(0, 1)
slicedAry[0][0] = 100
console.log(ary) // [ [ 100, 2, 3 ], [ 4, 5, 6 ] ]

Buffer.isBuffer

js
const buffer = Buffer.from('foo')

console.log(Buffer.isBuffer(buffer)) // true

Buffer.isBuffer = function (v) {
  return v instanceof Buffer
}

Buffer.concat

js
const b1 = Buffer.from('foo')
const b2 = Buffer.from('bar')
const b3 = Buffer.concat([b1, b2], 6)
console.log(b3.toString()) // foobar

Buffer.concat = function (bufferList, length) {
  if (length === undefined) {
    length = 0
    for (let i = 0, l = bufferList.length; i < l; i++) {
      length += bufferList[i].length
    }
  }

  const buffer = Buffer.alloc(length)

  for (let i = 0, l = bufferList.length, prev = 0; i < l; i++) {
    const b = bufferList[i]
    const length = b.length

    b.copy(buffer, prev)
    prev += length
  }

  return buffer
}