节点 js 缓冲区翻转二进制位

node js Buffer Flip Binary Bits

我正在用 nodejs 进行一些解码,并且有一个缓冲区:

59 19 F2 92  8C 88 88 88  89 88 EB 89  88 88 A1 8A 
88 88 88 88  89 88 A8 CD  88 88 88 DB  88 88 88 DC 
88 88 88 A5  88 88 88 BD  88 88 88 B2  88 88 88 B8 
88 88 88 B8  88 88 88 8A  88 89 89 8D  88 89 8D 8E 
88 89 89 8F  88 89 89 80  88 8C 87 88  88 88 81 88 
89 8B 82 88  8C 9C 88 88  88 85 88 8C  88 88 88 88 
87 88 89 8A  99 88 89 88  9B 88 8C 8D  88 88 88 9C 
88 8C 8D 88  88 88 9D 88  8C 8D 88 88  88 9E 88 8C 
A0 88 88 88  9F 88 94 DA  88 88 88 ED  88 88 88 FE 
88 88 88 ED  88 88 88 FA  88 88 88 FB  88 88 88 ED 
88 88 88 90  88 90 C4 88  88 88 E1 88  88 88 EF 88 
88 88 E0 88  88 88 FC 88  88 88 FB 88  88 88 91 88 
AC C4 88 88  88 ED 88 88  88 EE 88 88  88 FC 88 88 
88 A8 88 88  88 DC 88 88  88 FD 88 88  88 FA 88 88 
88 E6 88 88  88 92 88 A0  DA 88 88 88  E1 88 88 88 
EF 88 88 88  E0 88 88 88  FC 88 88 88  A8 88 88 88

需求文档说它是针对 0x77 对字节进行异或编码,然后取互补字节。

所以

59 XOR 77 => 2E (00101110) => D1 (11010001)
19 XOR 77 => 6E (01101110) => 91 (10010001)

节点中执行此操作并以包含所需字节的缓冲区结束的最佳方法是什么?

你可以试试这个:

let buf = new Buffer([ 0x59, 0x19, 0xF2, 0x92 ]); // etc.
let converted = new Buffer(
    Array.from(buf)
        .map(x => x ^ 0x77)
        .map(x => ~x)
);

// output: <Buffer d1 91 7a 1a>

这可能不是最快的方式(Array.from而不是一个一个地迭代缓冲区可能更慢,我选择了2个单独的地图而不仅仅是 1 以提高可读性),但它至少应该让你开始。

在功能上是正确的并且得到了我的赞成票。

然而,正如他们指出的那样,他们的解决方案“可能更慢”(它相当慢——尽管对于较小的缓冲区来说可以忽略不计)。按位运算符使用 32 位寄存器执行计算,但如果逐字节执行此位操作,它将花费 4 倍的操作。在此之上。 Array built in functions like .map and .forEach 正在为这种低级处理在幕后做很多乏味和不必要的事情(这些方法面向不变性和函数式编程——在执行期间在幕后进行大量数据复制)。

如果您正在进行二进制操作,您很可能希望改为执行以下操作:

// presuming `buffer` has your raw binary buffer
let wrapperUint32Array = new Uint32Array(buffer)
let end = wrapperUint32Array.length;
let i = 0;
while(i < end){
    wrapperUint32Array[i] = ~(0x77777777 ^ wrapperUint32Array[i])
    i++;
}

// your original buffer was manipulated/contains inverted bytes

不过,同样重要的是要注意,以上仅在缓冲区可被 4 整除且没有余数的情况下才有效。如果不是,但缓冲区中有偶数个字节,则可以改用 Uint16。如果是奇数,则 Uint8 也需要像下面这样使用。我们将执行更多操作(数量与 Array 映射相似),但没有数据被复制,并且使用这种方法迭代仍然更快。

// presuming `buffer` has your raw binary buffer
let end = buffer.byteLength;
let i = 0;
let wrapperUint8Array = new Uint8Array(buffer)
while(i < end){
    wrapperUint8Array[i] = ~(0x77 ^ wrapperUint8Array[i])
    i++;
}

// your original buffer was manipulated/contains inverted bytes

一些要点:

  • 我们正在充分利用 32 位运算符
  • 缓冲区在类型化数组中共享 -- 没有数据被复制
  • 缓冲区的迭代对于性能来说是最佳的