Java读取二进制文件(unsigned long long)

时间:2013-11-21 12:56:29

标签: java c++ binaryfiles endianness

我想将C代码转换为Java。它读取二进制文件:

int main(int argc, char**argv)
{
    FILE *fd;
    unsigned long trameNumber = 0;
    unsigned long long INDEX;

    fd = fopen(argv[1],"rb");
    if (fd == NULL)
    {
        printf("Usage %s [File]\n", argv[0]);
        exit(1);
    }

    fread(&INDEX, sizeof(INDEX),1, fd);
    printf("INDEX %llx\n",INDEX);
    trameNumber++;

    while (fread(&INDEX, sizeof(INDEX),1, fd) != 0)
    {
        printf("INDEX %llx\n",INDEX);
        trameNumber++;
    }

    fclose(fd);
    printf("%lu", trameNumber);

    return 0;
}

此代码的输出如下所示:

INDEX 0
INDEX 9800000000000000
INDEX 1801000000000000
INDEX 5001000000000000
INDEX b801000000000000

这是我的Java代码。我试图用BigInteger

来做到这一点
public static final int DATA_BYTE_LENGHT = 8;

public void readBinary(final String readFilePath)
{
    // A 8 byte buffer = 64 bits
    ByteBuffer byteBuffer = ByteBuffer.allocate(DATA_BYTE_LENGHT);

    // Those channels will be used to read/write files
    FileChannel channelFileInput = null;

    BigInteger bigIndex = null;

    try {

        // File to read
        final File fileRead = new File(readFilePath);

        // Channel used to read the file.
        channelFileInput = new FileInputStream(fileRead).getChannel();

        byteBuffer.put(new byte[DATA_BYTE_LENGHT]);
        byteBuffer.rewind();

        // While the file has content
        while( channelFileInput.read(byteBuffer) != -1 ) {

            byteBuffer.rewind();

            // Big integer positive
            bigIndex = new BigInteger(1, byteBuffer.array());

            byteBuffer.rewind();

            System.out.println("INDEX "+bigIndex.toString(16));

            // Clear the buffer
            byteBuffer.put(new byte[DATA_BYTE_LENGHT]);
            byteBuffer.rewind();

        }

    } catch(FileNotFoundException e) {
        System.err.println("The file cannot be read: "+e.getMessage());
    } catch(Exception e) {
        System.err.println(e.getMessage());
    } finally {
        // Close file connections
        IOUtils.closeQuietly(channelFileInput);
    }
}

但是,read()似乎无法正确读取文件。因为输出是:

INDEX 0
INDEX 98
INDEX 118
INDEX 150
INDEX 1b8

这可能是一个结束问题吗?怎么解决?

由于

2 个答案:

答案 0 :(得分:1)

BigInteger构造函数假定为big-endian表示,而文件中的数据似乎以little-endian存储。要解决此问题,您可以反转所获得的数组中的字节,或使用order中的ByteBuffer方法设置字节顺序并使用long数据类型:

// before loop
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);

// in loop
long bigIndex = byteBuffer.getLong();
byteBuffer.rewind();
System.out.println("INDEX "+Long.toHexString(bigIndex));

但Java的long数据类型已签名。这可能是也可能不是问题,取决于您之后想要对数字做什么。

更新:如果您必须使用BigInteger,您可以像我之前所说的那样反转字节数组,或者使用long读取数字,然后更正符号:

BigInteger bi = BigInteger.valueOf(bigIndex & ~Long.MIN_VALUE);
if (bigIndex < 0) bi = bi.setBit(63);

答案 1 :(得分:0)

Java将所有原始数据类型定义为使用big endian。如果您正在使用x86(Windows或Linux或OSX)平台,则您的计算机可能使用小端。 Endianess可能是你痛苦的原因。您可以使用掩码和移位操作来解决问题,以反转字节顺序。答案实际上是在this answer

中给出的