使用按位运算符将字节转换为int

问题描述 投票:0回答:2

我正在用Java编写一些代码。在提出疑问之前,我会给大家一些背景信息。目的是读取和处理orsm file,这是一个包含十六进制代码的文件。

流程如下:使用ByteBuffer将某个字节读入FileChannel。缓冲区填满后,将每个字节转换为有符号整数。这是使用按位&运算符和有符号左移运算符<<完成的,如下所示:

return  (0x000000ff & (bb.get() << 0)) |
        (0x0000ff00 & (bb.get() << 8)) |
        (0x00ff0000 & (bb.get() << 16)) |
        (0xff000000 & (bb.get() << 24));

bb当然是ByteBuffer。我完全不知道此代码的工作方式和原因,我用Google搜索了一下,发现最接近的问题是以下堆栈溢出问题:Converting java method to C#: converting bytes to integers with bit shift operators。还是我一无所知,我想知道是否有人可以帮助我找出此代码片段?

java int bit-manipulation byte bytebuffer
2个回答
6
投票

这将从底层字节缓冲区中读取四个字节,并将它们缝合在一起,成为一个int值,如下所示:

                        11111111 (first byte read)
                22222222         (second byte read)
        33333333                 (third byte read)
44444444                         (fourth byte read)

为实现这一点,对所有子结果执行按位或运算,其中每个子结果在上图中准备一行。例如,第三行准备为

(0x00ff0000 & (bb.get() << 16))

执行以下操作:

  1. 读取字节:

    xxxxxxxx
    
  2. byte展开为int

    000000000000000000000000xxxxxxxx        
    
  3. 将位向左移动16个插槽:

    00000000xxxxxxxx0000000000000000
    
  4. 最后,将其压入一个AND掩码,该掩码仅允许x位通过。这是必需的,因为byte已签名,因此实际上转换为int可能会导致以下结果:

    111111111111111111111111xxxxxxxx
    

如果执行恒定的AND掩码,则代码可能会更简单before shifting:

(bb.get() & 0xFF) << 16

这实际上是这些位操作中Java的标准习惯用法。


尽管不是您所提问题的答案,但肯定会首选使用提供的API(getInt方法)。您的字节顺序是小尾数,因此只需要设置它即可:

bb.order(ByteOrder.LITTLE_ENDIAN);

供参考,这是JDK的相同代码的实现:

static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
    return (((b3       ) << 24) |
            ((b2 & 0xff) << 16) |
            ((b1 & 0xff) <<  8) |
            ((b0 & 0xff)      ));
}

0
投票

[基本上,它读取四个字节,每个字节为八位,并将它们组合在一起成为32位的整数。它通过将每个连续字节向左移动额外的8位来完成此操作,因此将读取的第一个字节放入整数(0-7)的最后8位(最低顺序);下一个字节进入下一个8位(15-8),依此类推。

尽管使用ByteBuffer的实际功能执行此操作会容易得多:

bb.order(ByteOrder.LITTLE_ENDIAN); // Called once on the buffer
int intFromNextFourBytes = bb.getInt(); // Read the same value as your code.
© www.soinside.com 2019 - 2024. All rights reserved.