我正在用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。还是我一无所知,我想知道是否有人可以帮助我找出此代码片段?
这将从底层字节缓冲区中读取四个字节,并将它们缝合在一起,成为一个int
值,如下所示:
11111111 (first byte read)
22222222 (second byte read)
33333333 (third byte read)
44444444 (fourth byte read)
为实现这一点,对所有子结果执行按位或运算,其中每个子结果在上图中准备一行。例如,第三行准备为
(0x00ff0000 & (bb.get() << 16))
执行以下操作:
读取字节:
xxxxxxxx
将byte
展开为int
:
000000000000000000000000xxxxxxxx
将位向左移动16个插槽:
00000000xxxxxxxx0000000000000000
最后,将其压入一个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) ));
}
[基本上,它读取四个字节,每个字节为八位,并将它们组合在一起成为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.