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 バイトのうち何バイトが意味を持つかを示していることに注意してください。

もう1つ気をつけたいのはアライメントです。質問で説明されているように、レコードは整列しているように見えます。そうであるかどうかは、Delphi コンパイラの設定に依存します。Delphi コンパイラがレコードをパックするように指示された可能性があります。

ないと仮定しましょう。つまり、レコードが整列されていると仮定しましょう。フィールドを正しく整列させるために、フィールドInt64は 8 バイト境界で整列されます。つまり、レコードのレイアウトは次のようになります。

オフセット長フィールド
 0 9 FileType、長さ 1 バイト、ペイロード 8 バイト
 9 7 <パディング>
16 8 ポイント
24 8 オブジェクト
32 8 テキスト
40 1 オブジェクトレイヤー
41 1 テキストレイヤー
42 6 <パディング>

レコードの最後にパディングがあるため、レコードの全長は 48 です。レコードの最後のパディングをスキップしないと、ファイル内の次に来るものを読み取るのに間違った場所にいることになるため、これは重要です。

出力をざっと調べてみると、レコードがパックされているのではなく、実際に整列されていることがわかります。コードの 2 番目のブロックは 40 バイトを読み取り、次の 2 バイト (オフセット 41 と 42) は 11 と 4 で、上の表と一致します。

最後に注意すべき点は、これらのファイルを生成した Delphi はリトル エンディアンの整数を使用している可能性が高いということです。Java はビッグ エンディアン (と私は信じています) であるため、整数フィールドに対してリトル エンディアンからビッグ エンディアンへの変換を実行する必要があります。たとえば、 を使用しjava.nio.ByteBufferます。

この仮説を確認してみましょう。読み取った 3 つの long には次の値があると述べています。

6538107356104884224
5276531012929585152
7653586091739447296

16 進数に変換すると、次のようになります。

5ABC060000000000
493A010000000000
6A37000000000000

バイトを逆にしましょう (先頭のゼロバイトをスキップします):

6BC5A
13A49
376A

10進数で

441434
80457
14186

そして、それらはあなたの望ましい値です。ふぅ、ついにたどり着きました!

于 2013-10-27T15:19:38.787 に答える