tags:

views:

439

answers:

4

I am trying to read a binary file from a program that writes a log (of sorts) to a dat file which I have worked out reasonably well the format of using Java. I am loading it as so:

DataInputStream in = new DataInputStream(new FileInputStream("file.dat"));

System.out.println("Bytes skipped: " + in.skipBytes(4));

System.out.println(in.readLong());

The problem is the value from readLong() is different to what I am expecting, in Hex Workshop I highlight the hex blocks

BF02 0000

and reports that it is a valid signed short/long number - however the output is very different to what I am expecting. Looking at the Java Docs it states that it classes a long as 64 bit (8 bytes) whereas other sources show a signed long integer should be 32 bits - is there a way to get around this?

Cheers,

Tom

+2  A: 

A long in Java is always 8 bytes (64 bits). Different languages and platforms use different terminology. If you want to read 4 bytes, read an int.

Jon Skeet
So long as it's a big-endian int...
Tom Hawtin - tackline
+2  A: 

primitive types means different things in different languages and different platforms. (e.g. In C, it's not uncommon that a a long is 32 bit on some platforms and 64bits on others.

First you have to know the type in your .dat file, and the byte order (big/little endian). Then assemble the individual bytes into an appropriate java type. If the .dat files specifies a 32 bit signed integer, an int in java would be suitable. If it was an unsigned 32 bit integer, you probably would need to use a long in java to capture all the possible values, since java does not have unsigned types.

Read it as follows if the integer in the file is little endian:

 int i = (in.readByte()) | (in.readByte() << 8) | (in.readByte() << 16) | (in.readByte() << 24)

and if it's big endian, do

int i = (in.readByte() << 24) | (in.readByte() << 16) | (in.readByte() << 8) | (in.readByte())

(I don't remember atm. the promotion rules in java here, you might need to and them with &0xff to produce an int before the bit shifting) Of course, you can read in a byte array and operate on that array instead of calling in.readByte() individually if you want.

nos
Or Integer.reverseBytes(), Long.reverseBytes(). At least they are sorter to type.
kd304
A: 

If you use Preon, then you don't have to do all of the shifting and masking. In the class reflecting the encoded data structure, you simply mark some field as a bound numeric value, and that's mostly it.

class EncodedDataStructure {

  @BoundNumber
  private long theLong;

}

And if you want to read 4 bytes only, but still want it to be a long:

@BoundNumber(size="32") // Size is number of bits
private long theLong;

Or if you want to force it to be big or little endian:

@BoundNumber(size="32", byteOrder=Endian.Big)
private long theLong;

... and you read it like this:

Codec<EncodedDataStructure> codec = Codecs.create(EncodedDataStructure.class);
EncodedDataStructure structure = Codecs.decode(codec, file);
Wilfred Springer
A: 

You can use ByteBuffer when reading the data and change the byte order with the order() method.

Peter Lawrey