将4个字节转换为一个未签名的32位整数,并长时间存储



我正在尝试读取Java中的二进制文件。我需要读取未签名的8位值,未签名的16位值和未签名的32位值的方法。这样做的最好(最快,最好的代码)是什么?我在C 中做到了这一点,并做了这样的事情:

uint8_t *buffer;
uint32_t value = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24;

但是在Java中,如果例如Buffer [1]包含一个值,该值是左移的结果是INT(?),则会引起问题。而不是或:在特定位置仅在0xa5中或:s in 0xffffa500或类似的东西,"损坏"两个顶部字节。

我现在有一个代码,看起来像这样:

public long getUInt32() throws EOFException, IOException {
    byte[] bytes = getBytes(4);
    long value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
    return value & 0x00000000FFFFFFFFL;
}

如果我想转换四个字节0x67 0xa5 0x72 0x50结果是0xffffa567而不是0x5072a567。

编辑:这很棒:

public long getUInt32() throws EOFException, IOException {
    byte[] bytes = getBytes(4);
    long value = bytes[0] & 0xFF;
    value |= (bytes[1] << 8) & 0xFFFF;
    value |= (bytes[2] << 16) & 0xFFFFFF;
    value |= (bytes[3] << 24) & 0xFFFFFFFF;
    return value;
}

但是没有更好的方法吗?对于这样的简单事物,10个比特操作似乎是一个"小"。

更常规的版本将字节转换为其无符号值,因为整数首先:

public long getUInt32() throws EOFException, IOException {
    byte[] bytes = getBytes(4);
    long value = 
        ((bytes[0] & 0xFF) <<  0) |
        ((bytes[1] & 0xFF) <<  8) |
        ((bytes[2] & 0xFF) << 16) |
        ((long) (bytes[3] & 0xFF) << 24);
    return value;
}

不要挂在位操作的数量上,很可能编译器会优化这些字节操作。

另外,您不应该仅将long用于32位值只是为了避免符号,您可以使用int并忽略大部分时间签名的事实。看到此答案。

更新:需要将最重要字节的铸件变为长期,因为否则将其最重要的位转移到32位整数的符号中,有可能使其负面。<<<<<<<<<<<<<<<<<<

您有正确的想法,我认为没有明显的改进。如果您查看java.io.DataInput.readInt规格,则它们具有同一件事的代码。他们切换<<&的顺序,但以其他方式进行标准。

除非您使用内存映射的区域,否则无法从byte数组中读取int,这是 Way

当然,您可以直接使用DataInputStream而不是首先使用byte[]

DataInputStream d = new DataInputStream(new FileInputStream("myfile"));
d.readInt();

DataInputStream在相反的端度上工作,因此您还需要一些Integer.reverseBytes调用。它不会更快,但是更干净。

最新更新