在Delphi上读取JAVA生成的二进制文件
我已经从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
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,这里有两个问题
TDateTime
- 查找或编写一些帮助工具来处理endian问题。读取数据后立即从大端到小端转换
- 将日期读取为64位整数。然后,您需要计算出Java纪元是什么,并将自Java纪元起的毫秒转换为Delphi
,它度量自Delphi纪元起经过的天数TDateTime
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。