mabg
mabg

Reputation: 2092

Read binary file generated from JAVA on Delphi

I've generated a binary file from JAVA:

RandomAccessFile out = new RandomAccessFile(file, "rwd");
out.writeLong(calendar.getTimeInMillis());
out.writeDouble(double1);
out.writeDouble(double2);
out.writeDouble(double3);

How can I read this information from Delphi 2007?

I've tried something like this:

type TData = record
  time: TDateTime;
  double1: double;
  double2: double;
  double3: double;
end;
var
   data: TData;
   F : file of TData;
begin
  AssignFile(F,fileName) ;
  Reset(F) ;
  Read (F, data);
...

but the values of time, double1, double2 and double3 are completly different.

Upvotes: 2

Views: 780

Answers (4)

mabg
mabg

Reputation: 2092

Finally the solution is:

function Swap8ToDouble(A:double): double;
var
  hold:double;
asm
  mov edx,dword ptr[A]
  mov ecx,dword ptr[A+4]
  bswap edx
  bswap ecx
  mov dword ptr [hold],ecx
  mov dword ptr [hold+4],edx
  fld hold;
end;

function Int64Swap(A: int64): int64;
asm
  mov edx,dword ptr [A]
  mov eax,dword ptr [A+4]
  bswap edx
  bswap eax
end;


type TData = record
    time: Int64;
    double1: double;
    double2: double;
    double3: double;
end;

...

data.time := UnixToDateTime(Int64Swap(data.time) div 1000);
data.double1 := Swap8ToDouble(data.double1);
data.double2 := Swap8ToDouble(data.double2);
data.double3 := Swap8ToDouble(data.double3);

Upvotes: 2

David Heffernan
David Heffernan

Reputation: 613053

There are two issues here.

  1. Java is big endian and Delphi is little endian.
  2. The Java code writes the date as a 64 bit integer. The Delphi code reads a floating point TDateTime.

Assuming you are going to change the Delphi code rather than the Java code, here's what you would do to bring the two sides together:

  • Find or write some helper utilities to deal with the endian issue. Convert from big endian to little endian as soon as you read the data.
  • Read the date as a 64 bit integer. Then you need to work out what the Java epoch is and convert from milliseconds since the Java epoch into a Delphi TDateTime which measures days elapsed since the Delphi epoch.

Dealing with endianness is simple enough, albeit rather tiresome.

The time conversion is perhaps a little more involved. The key information is that the Java epoch is the same as the Unix epoch. So a function that converts Unix time to Delphi TDateTime is all you need. Fortunately the Delphi RTL supplies the very function. It's in the DateUtils unit and is named UnixToDateTime. Note that UnixToDateTime receives a Unix time measured in seconds so you'll need to divide your value in milliseconds by 1000.

One other point that I would make is that the Java code writes the data out with no gaps between fields. But the Delphi code uses an aligned record. Now, since all the members are the same size, there is no padding in this case. But it's something to watch out for. If I were you I would not be using legacy Pascal I/O to read this. I'd use a binary reader class that operates in a similar way to your Java writer. And I'd use that reader to read in the fields one at a time.

There may be something to be gained from finding (or writing) a reader class that handles the endian conversion for you.

Upvotes: 2

jachguate
jachguate

Reputation: 17203

Your primary logic is OK but, since you're writing and reading binary data, you have to maintain DataType compatibility between the writer and the reader, and you also have to take endianness of writer and reader.

The java calendar.getTimeInMillis() returns a long, the Delphi equivalent is Int64, whereas Double is equivalent in both (64 bit IEEE), so your record should look like this:

type TData = record
  Millis: Int64;
  double1: double;
  double2: double;
  double3: double;
end;

Upvotes: 0

user18428
user18428

Reputation: 1201

calendar.getTimeInMillis() returns a long.

Your best bet if using delphi 7+ is a UInt64 to match java long

See here for java primitive datatypes descriptions and try to match to delphi datatypes

edit : As David Heffernan noticed you'll also have to convert endianness

Upvotes: 3

Related Questions