ArrayBuffer 按位数存取数字

Table of Contents

JavaScript ArrayBuffer 数据类型进行二进制操作。但对于 ArrayBuffer 的操作最小粒度是字节,比如 Uint8Array。每一位元素都是一个字节。想要进行按位读写的操作就需要自己编写相关方法。每当有此种需求都编写一遍很麻烦,也烧脑。所以这篇文章记录一下,下次直接复制。

代码

/**
 * 针对 Uint8Array 进行位操作
 * 包括读取、写入指定位范围的数据
 **/
const BitKit = {
  
  // 一个数最多需要多少二进制位
  getBitsByNum(num) {
    let exp = 1
    while (num > 2 ** exp) {
      exp++
    }
    return exp
  },
  /**
   * 按位数读数据
   * @param {Uint8Array} buf
   * @param {number} start 开始位
   * @param {number} [bits] 读取的位数
   * @return number
   **/
  read(buf, start, bits = 1) {
    let startByte = (start / 8) >> 0
    let leftBits = bits
    let startBit = start % 8
    let res = 0
    let isFirst = true
    while (leftBits > 0) {
      // 当前字节剩余位数
      const currByteNotUsedBits = 8 - startBit
      // 当前字节取值位数
      const readBits = leftBits > currByteNotUsedBits ? currByteNotUsedBits : leftBits
      // 如果不是第一次取值,需要把已经取的值左移
      if (!isFirst) {
        res = res << readBits
      }
      isFirst = false
      res += (buf[startByte] >> (currByteNotUsedBits - readBits)) & ((1 << readBits) - 1)
      // 剩余需要字节
      leftBits -= readBits
      startBit = 0
      startByte++
    }
    return res
  },
  
  /**
   * 按位数存数据
   * @param {Uint8Array} buf
   * @param {number} num
   * @param {number} start 开始位
   * @param {number} [bits] 写入的位数
   * @return number buf 下一个空位
   **/
  write(buf, num, start, bits = 0) {
    let startByte = (start / 8) >> 0
    let leftBits = bits = bits === 0 ? this.getBitsByNum(num) : bits
    let startBit = start % 8
    console.log(leftBits, startBit)
    while (leftBits) {
      // 当前字节剩余位数
      const currByteNotUsedBits = 8 - startBit
      // 当前字节需要填充位数
      const fillBits = currByteNotUsedBits >= leftBits ? leftBits : currByteNotUsedBits
      // 数字剩余位数
      leftBits -= fillBits
      // 取 num 的指定位数的值
      const partNum = (num >> leftBits) & ((1 << fillBits) - 1)
      // 存入当前字节
      buf[startByte] = buf[startByte] | (partNum << (currByteNotUsedBits - fillBits))
      startBit = 0
      startByte++
    }
    return start + bits
  }
}

解读

BitKit.getBitsByNum 可以获取某个数字需要的位数。比如 124 需要 7 比特位才能放得下。

BitKit.read 读取指定位置的数据。比如:BitKit.read(uint8Buf, 3, 7) 就是从 uint8Buf 的第四位(下标从 0 开始)读取 7 个比特位。

BitKit.write 在指定位置写入数据。比如:BitKit.write(uint8Buf, 123, 3) 就是把数字 123 写入到 uint8Buf——从第四个比特位开始。