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