Java 中将位打包到 byte[] 并读回的最有效方法是啥?

Posted

技术标签:

【中文标题】Java 中将位打包到 byte[] 并读回的最有效方法是啥?【英文标题】:What is the most efficient way in Java to pack bits into byte[] and read it back?Java 中将位打包到 byte[] 并读回的最有效方法是什么? 【发布时间】:2011-11-28 02:42:18 【问题描述】:

我目前使用这两个函数来打包和读取字节数组中的位。想知道是否有人有更好的想法或更快的方法来做到这一点?

对程序进行了一些优化,并列出了一些计算。目前 1 亿次 Put 和 Get 需要大约 12 秒,而不是现在的 16 秒。

如果有人使用当前代码,请确保传递给 Put 的值是一个正数,因为它预计会出现无符号数。如果有兴趣,我可以提供签名和未签名的版本。

class BitData

    static void Put(byte Data[], final int BitOffset, int NumBits, final int Value)
    
        final long valLong=(Value&((1L<<NumBits)-1L));
        int posByte=BitOffset>>3;
        int posBit=BitOffset&7;
        int valByte;
        int ModifyBits;

        long lValue;
        int LeftShift;
        ModifyBits=8-posBit;
        if(NumBits<ModifyBits) ModifyBits=NumBits;
        LeftShift=(8-posBit-ModifyBits);
        while(true)
        
            valByte = Data[posByte];
            if(ModifyBits==8)
            
                lValue=valLong<<(32-NumBits)>>(24);
                Data[posByte]=(byte)lValue;
            
            else
               
                lValue=valLong<<(32-NumBits)>>(32-ModifyBits)<<LeftShift;
                Data[posByte]=(byte)((valByte & ~(((1<<ModifyBits)-1) << LeftShift)) | lValue);
            
            NumBits-=ModifyBits;
            if(NumBits==0) break;
            posByte++;          
            ModifyBits=8;
            if(NumBits<ModifyBits) 
            
                ModifyBits=NumBits;
                LeftShift=(8-ModifyBits);
            
        
    

    static int GetInt(byte Data[], final int BitOffset, int NumBits)
           
        int posByte=BitOffset>>3;
        int posBit=BitOffset&7;


        long Value=0;
        int ModifyBits;
        int valByte;
        int LeftShift;
        ModifyBits=8-posBit;
        if(NumBits<ModifyBits) ModifyBits=NumBits;
        LeftShift=(8-posBit-ModifyBits);
        while(true)
        
            valByte = Data[posByte] & 0xff;
            if(ModifyBits==8) Value+=valByte;
            else Value+=(valByte & ((1<<ModifyBits)-1) << LeftShift) >> LeftShift;              
            NumBits-=ModifyBits;
            if(NumBits==0) break;
            posByte++;
            ModifyBits=8;
            if(NumBits<ModifyBits) 
            
                ModifyBits=NumBits;
                LeftShift=(8-ModifyBits);
            
            Value<<=ModifyBits;

        
        return (int)Value;
    

【问题讨论】:

你考虑过使用内置的java.util.BitSet吗? 是的,首先尝试过。它比这种方法慢了很多。它是一个需要每秒打包和解包数百万个数据包的服务器,因此需要尽可能快的方法来完成它。我已经对这两个函数进行了尽可能多的优化。只是好奇是否有一条我在 Java 中没有想到的完全不同的路线。 是的。用 C 编写并使用 JNI 将其与 Java 接口。 程序也需要可移植。我不熟悉JNI。如果我走那条路,你能告诉我程序是否仍然可以在不同的操作系统服务器上运行吗? @JimGarrison - 您是否有任何基准测试表明如此小的计算的加速将超过进行 JNI 方法调用的开销? (对 OP - 我认为这是个坏建议。) 【参考方案1】:

完全不同的方法是定义所有可能组合的静态表并执行查找而不是每次都计算结果。我认为这就是他们在密码学中的做法。 array[i] x 3 应该比 numBits 位运算快得多。不过它会占用一些堆。

【讨论】:

将尝试整理一些零件,看看是否有速度提升。 我添加的两个表似乎将性能提高了大约 7-10%。在代码中找不到适合表格的任何其他内容。 10% 的收益还是不错的。

以上是关于Java 中将位打包到 byte[] 并读回的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

UPDATE BINARY 并读回写入的块

libnfc:从 NTAG 写和读回自定义数据

在 Hibernate 中将 Java byte[] 映射到 MySQL binary(64)

在 Java 中将 long 转换为字节

读取和写入 NSMutableDictionary 到 plist 文件

Delphi 组件序列化