Reputation: 2533
I want to convert a C code to Java. It reads a binary file:
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;
}
The output with this code looks like:
INDEX 0
INDEX 9800000000000000
INDEX 1801000000000000
INDEX 5001000000000000
INDEX b801000000000000
Here is my Java code. I've tried to do that with 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);
}
}
However, read()
doesn't seem to read the file correctly. Because the output is:
INDEX 0
INDEX 98
INDEX 118
INDEX 150
INDEX 1b8
Could it be an endianess problem? How to solve it?
Thanks
Upvotes: 1
Views: 1712
Reputation: 111219
The BigInteger
constructor assumes a big-endian representation, while the data in the file seems to be stored in little-endian. To fix this problem you can reverse the bytes in the array that you obtain, or use order
method in ByteBuffer
to set the endianness and use the long
data type:
// before loop
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
// in loop
long bigIndex = byteBuffer.getLong();
byteBuffer.rewind();
System.out.println("INDEX "+Long.toHexString(bigIndex));
Java's long
data type is signed though. This may or may not be a problem depending on what you want to do with the numbers afterwards.
Update: If you must use BigInteger
you can just reverse the array of bytes like I said earlier, or read the numbers using long
and then correct the sign:
BigInteger bi = BigInteger.valueOf(bigIndex & ~Long.MIN_VALUE);
if (bigIndex < 0) bi = bi.setBit(63);
Upvotes: 1
Reputation: 4554
Java defines all primitive data types as using big endian. If you are working on an x86 (windows or linux or OSX) platform, your computer is likely using little endian. Endianess is likely the cause of your affliction. You can probably solve the problem using mask and shift operations to reverse the byte order. The answer to this is actually given in this answer
Upvotes: 0