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——从第四个比特位开始。