2

我从 JAVA 生成了一个二进制文件:

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

如何从 Delphi 2007 读取这些信息?

我试过这样的事情:

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);
...

但是 time、double1、double2 和 double3 的值完全不同。

4

4 回答 4

3

calendar.getTimeInMillis() 返回一个 long。

如果使用 delphi 7+,你最好的选择是 UInt64 来匹配 java long

有关 java 原始数据类型的描述,请参见此处并尝试与 delphi 数据类型匹配

编辑:正如大卫赫弗南注意到的那样,你还必须转换字节序

于 2013-03-26T15:01:49.873 回答
2

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.

于 2013-03-26T15:02:49.167 回答
2

最后的解决方案是:

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);
于 2013-03-26T17:50:57.657 回答
0

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;
于 2013-03-26T15:03:24.060 回答