node js Buffer Flip Binary Bits

时间:2016-04-01 23:02:55

标签: javascript node.js buffer

我正在进行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

需求文档说它在字节编码XOR与0x77然后取互补字节。

所以

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

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

2 个答案:

答案 0 :(得分:2)

你可以试试这个:

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个为了便于阅读)但它至少应该让你开始。

答案 1 :(得分:1)

dvlsg's answer 在功能上很到位并收到了我的赞成票。

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

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

// 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,如下所示。我们将执行更多操作(在数量上类似于数组映射),但不会复制任何数据,并且使用这种方法迭代仍然要快得多。

// 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 位运算符
  • 缓冲区在类型化数组中共享——没有数据被复制
  • 缓冲区的迭代对性能来说是最佳的