读取Delphi上从JAVA生成的二进制文件

时间:2013-03-26 14:54:15

标签: java delphi type-conversion

我已经从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 个答案:

答案 0 :(得分:3)

calendar.getTimeInMillis()返回一个长。

如果使用delphi 7+是一个匹配java long

的UInt64,最好的选择

有关java原始数据类型的描述,请参阅here并尝试匹配delphi数据类型

编辑:正如David Heffernan注意到你还必须转换字节序

答案 1 :(得分:2)

这里有两个问题。

  1. Java是大端,Delphi是小端。
  2. Java代码将日期写为64位整数。 Delphi代码读取浮点TDateTime
  3. 假设您要更改Delphi代码而不是Java代码,那么您可以采取以下措施将双方联系起来:

    • 查找或编写一些帮助程序实用程序来处理endian问题。一读完数据就立即从大端转换为小端。
    • 将日期作为64位整数读取。然后你需要弄清楚Java纪元是什么,并从Java纪元以来的毫秒转换成Delphi TDateTime,它测量自德尔福纪元以来的几天。

    处理字节序很简单,虽然相当无聊。

    时间转换可能更多一些。关键信息是Java纪元与Unix纪元相同。因此,您只需要一个将Unix时间转换为Delphi TDateTime的函数。幸运的是,Delphi RTL提供了非常好的功能。它位于DateUtils单元中,名为UnixToDateTime。请注意UnixToDateTime接收以秒为单位测量的Unix时间,因此您需要将您的值除以1000为单位。

    我要做的另一点是Java代码将数据写出来,字段之间没有间隙。但Delphi代码使用对齐记录。现在,由于所有成员的大小相同,因此在这种情况下没有填充。但值得注意的是。如果我是你,我不会使用传统的Pascal I / O来阅读它。我将使用二进制阅读器类,其操作方式与Java编写器类似。我会用那个读者一次一个地阅读这些字段。

    找到(或编写)为您处理endian转换的reader类可能会有所收获。

答案 2 :(得分: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);

答案 3 :(得分:0)

您的主要逻辑是正常的,但是,由于您正在编写和读取二进制数据,您必须保持编写器和阅读器之间的DataType兼容性,并且还必须采用编写器和阅读器的字节序。

java calendar.getTimeInMillis()返回long,Delphi等效于Int64,而Double在两者中都是等效的(64位IEEE),因此您的记录应如下所示:

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