2

我有一个由 Delphi 记录组成的二进制文件。记录如下:

TRMapFileHeader = record
    FileType: String[8];
    Points: Int64;
    Objects: Int64;
    Text: Int64;
    ObjLayers: byte;
    TextLayers: byte;
  end;

我想用 Java 阅读这个文件。我打开了文件:

DataInputStream file = new DataInputStream(new FileInputStream(filename))

然后我尝试读取数据:

for(int i = 0; i<8; i++)
    System.out.print((char)file.readByte());
System.out.println();
System.out.println(file.readLong());
System.out.println(file.readLong());
System.out.println(file.readLong());
System.out.println(file.readByte());
System.out.println(file.readByte());

我有

日食输出

而不是正确的数据,它们是:

RMF
441434
80457
14186
11
4

我尝试了不同的阅读方式,发现了下一个:

System.out.println(file.readByte());
for(int i = 0; i<3; i++)
    System.out.print((char)file.readByte());

for(int i = 0; i<36; i++)
    file.readByte();

System.out.println();
System.out.println(file.readByte());
System.out.println(file.readByte());

给出下一个输出: Eclipse 输出。第一个字节等于 3,然后是 3 个字符,然后是 36 个字节,然后是记录的最后 2 个参数

所以我想知道如何阅读这种记录

4

1 回答 1

6

Delphi 类型String[8]是一个短字符串。它的实现包含一个包含字符串长度的额外前导字节。因此,大小String[8]为 9 个字节。

您需要读取第一个字节来查找长度,然后读取接下来的 8 个字节来查找有效负载。请记住,第一个字节告诉您后续 8 个字节中有多少是有意义的。

另一件需要注意的是对齐。如问题中所述,记录似乎是一致的。它是否取决于 Delphi 编译器设置。Delphi 编译器可能被指示打包记录。

我们假设不是。换句话说,让我们假设记录是对齐的。为了使字段正确对齐,Int64字段将在 8 字节边界上对齐。这意味着记录的布局将如下所示:

偏移长度字段
 0 9 文件类型,1 字节长度,8 字节有效载荷
 9 7 <填充>
16 8 分
24 8 个对象
32 8 文本
40 1 个对象图层
41 1 文本图层
42 6 <填充>

由于记录末尾的填充,记录的总长度为 48。这很重要,因为如果您不跳过记录末尾的填充,那么您将在错误的位置读取文件中接下来的任何内容。

粗略检查您的输出将表明记录确实是对齐的而不是打包的。您的第二个代码块读取 40 个字节,然后接下来的两个字节(在偏移量 41 和 42 处)是 11 和 4,这与我上面的表格相匹配。

最后要注意的一点是,生成这些文件的 Delphi 很可能使用小端整数。Java 是大端(我相信),因此您需要对整数字段执行一点到大端的转换。例如使用java.nio.ByteBuffer.

让我们看看这个假设。您声明您阅读的三个 long 具有以下值:

6538107356104884224
5276531012929585152
7653586091739447296

并转换为十六进制我们有:

5ABC060000000000
493A010000000000
6A37000000000000

让我们反转字节(跳过前导零字节):

6BC5A
13A49
376A

十进制是

441434
80457
14186

这些是您想要的值。呼,我们终于到了!

于 2013-10-27T15:19:38.787 回答