我可以简化从二进制数据中读取短片吗

Can I simplify reading a short from binary data

我正在尝试简化一些用于解码文件中数据的代码,并且我已经编写了一个测试用例来说明这个问题。

给定两个字节 0xFe0xFF 我希望将其读作 0xFFFE (65534), 现有代码

headerBuffer.get() & 0xff + (headerBuffer.get() & 0xff) * 256

我想,如果我将缓冲区字节顺序设为小端,我可以通过短读来获得相同的结果。但是我没有得到相同的结果,为什么不呢?

headerBuffer.getShort();

public void testReadingOfShort() {
    ByteBuffer headerBuffer = ByteBuffer.allocate(2);
    headerBuffer.order(ByteOrder.LITTLE_ENDIAN);
    headerBuffer.put((byte) 0xFE);
    headerBuffer.put((byte)0xFF);
    headerBuffer.position(0);
    int format = headerBuffer.get() & 0xff + (headerBuffer.get() & 0xff) * 256;
    headerBuffer.position(0);
    int formatNew = headerBuffer.getShort();
    System.out.println("Format:"+format+"("+ Hex.asHex(format)+")"+":FormatNew:"
            +formatNew+"("+Hex.asHex(formatNew)+")");
}

输出

Format:65534(0xfffe):FormatNew:-2(0xfffffffffffffffe)

你确实得到了同样的价值。当您在此行将 short 分配给 int 时会出现问题:

int formatNew = headerBuffer.getShort();

执行此操作时,Java 执行 符号扩展 以确保 short 中的数值转换为相同的数值int。在您的情况下,即 -2.

-2表示为short0xFFFE,而int表示是0xFFFFFFFE。换句话说,short 的符号位被复制到 int 的附加高位。

您可以通过不将 short 分配给 int 来解决此问题。您还需要确保您的 Hex.asHexshort 有适当的重载,否则当 formatNew 作为参数传递时会发生相同的转换。

或者,如果您想将 short 的值视为无符号,并将其分配给 int,您可以使用 0xFFFF 屏蔽结果,如下所示:

int formatNew = headerBuffer.getShort() & 0xFFFF;

我的假设是,在您的 Hex class 中,您有一个 .asHex() 方法以 short 作为参数,它执行如下操作:

int value = (int) argument;

运气不好。如果您 "upcast" 从一种整数类型到另一种整数类型,则符号位(如果存在) 携带的。这意味着如果你尝试将 short 0xfffe 转换为 int,你将不会以 0x0000fffe 结束,而是...... 0xfffffffe。因此你的结果。

如果您想将其转换为无符号值,则必须将其屏蔽,如下所示:

int value = (int) argument & 0xffff;

您可以简单地获得所需的值

int formatNew = headerBuffer.getShort() & 0xFFFF;

或者,如果您使用 Java 8:

int formatNew = Short.toUnsignedInt(headerBuffer.getShort());

这基本上会删除 int 中不属于 short 的所有位。但这并不能免除您仔细检查期望无符号值的位置以及如何在相应上下文中处理(自然)带符号值的责任。