Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Delphi上读取JAVA生成的二进制文件_Java_Delphi_Type Conversion - Fatal编程技术网

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

在Delphi上读取JAVA生成的二进制文件,java,delphi,type-conversion,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 = recor

我已经从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);
...
type TData = record
  Millis: Int64;
  double1: double;
  double2: double;
  double3: double;
end;
但是时间、double1、double2和double3的值完全不同。

calendar.getTimeInMillis()返回一个长字符串

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

有关java基本数据类型的描述,请参阅,并尝试与delphi数据类型匹配


编辑:正如大卫·赫弗南(David Heffernan)所注意到的,您还必须转换endianness,这里有两个问题

  • Java是big-endian,Delphi是little-endian
  • Java代码将日期写入64位整数。Delphi代码读取浮点
    TDateTime
  • 假设您要更改Delphi代码而不是Java代码,下面是将两者结合在一起的方法:

    • 查找或编写一些帮助工具来处理endian问题。读取数据后立即从大端到小端转换
    • 将日期读取为64位整数。然后,您需要计算出Java纪元是什么,并将自Java纪元起的毫秒转换为Delphi
      TDateTime
      ,它度量自Delphi纪元起经过的天数
    处理endianness很简单,尽管相当烦人

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

    我要指出的另一点是,Java代码在字段之间没有间隙地写出数据。但是Delphi代码使用对齐的记录。现在,由于所有成员的大小都相同,因此在本例中没有填充。但这是值得注意的。如果我是你,我就不会使用遗留的Pascal I/O来阅读本文。我将使用一个二进制读取器类,其操作方式与Java编写器类似。我会用那个读卡器一次读一个字段


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

    您的主要逻辑是正常的,但是,由于您正在编写和读取二进制数据,您必须保持编写器和读取器之间的数据类型兼容性,并且还必须考虑编写器和读取器的endianness

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

    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);
    ...
    
    type TData = record
      Millis: Int64;
      double1: double;
      double2: double;
      double3: double;
    end;
    

    最后,解决方案是:

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

    我建议将记录打包,因为它是在没有与文件对齐的情况下写入的(现在这并不重要,因为所有记录成员都有8字节长,但将来可能会添加新值),它必须是二进制文件吗?比如说,使用xml,你可以大大简化事情。我认为你不应该使用ASM来处理endianness。顺便说一句,既然你是新来的,请接受你的评价中最好的答案。请看:代码的另一个问题是,信号nan将导致引发异常。您需要在不加载到FPU的情况下交换字节。您的代码不可移植,并且仅限于x86。