Dのファイルに生のバイナリ構造を書き込みますか?

Aug 19 2020

いくつかで定義されたいくつかのバイナリレコードを含むバイナリファイルを作成しようとしていますstruct。しかし、私はそれを行う方法を見つけることができないようです。他の例を見ると、string問題なくsを書くことができましたが、そうではありませんでしたstruct。私はちょうど私がでするようにそれを書きたいCfwrite(3)、しかしでDバージョン2。

これが私がこれまでに試したことです:

  • 使用してstream.write(tr)-人間が読める/デバッグ表現を書き込み、
  • 使用stream.rawWrite(tr)-これは私が必要としているもののように聞こえましたが、コンパイルに失敗しました:

エラー:テンプレートstd.stdio.File.rawWriteは、引数タイプ!()(TitleRecord)から関数を推測できません。候補は次のとおりです。

/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d(1132):std.stdio.File.rawWrite(T)(in T [] buffer)

  • rawWrite上記のように試みますが、データをさまざまなものにキャストしても、コンパイルされることはありません。
  • さえに戻って取得しようCfwriteしますが、ファイルディスクリプタIの必要性を得るために十分な深を取得することはできません。

ドキュメントを読むことはあまり役に立ちませんでした(文字列を書くことは私にとってもうまくいきますが、書くことはできませんstruct)。簡単な方法があるはずですが、見つけることができません。他のSOの質問は 役に立ちませんでした。私はD 1.0、それはで達成されたかもしれませんが、それはstream.writeExact(&tr, tr.sizeof)もはや選択肢ではありません。

import std.stdio;

struct TitleRecord {
        short id;
        char[49] text;
};

TitleRecord tr;

void main()
{
 auto stream = File("filename.dat","wb+");
 tr.id = 1234;
 tr.text = "hello world";
 writeln(tr);
 //stream.write(tr);
 //stream.rawWrite(tr);
 //stream.rawWrite(cast(ubyte[52]) tr);
 //stream.rawWrite(cast(ubyte[]) tr);
 //fwrite(&tr, 4, 1, stream);
}

回答

2 AdamD.Ruppe Aug 19 2020 at 21:40

このため、そのエラーは、構造体ではなく配列を予期していることを示しています。したがって、これを行う簡単な方法の1つは、ポインターをスライスしてrawWriteに渡すことです。

stream.rawWrite((&tr)[0 .. 1]);

(&tr)これポインタにあなたの構造体を変換し、アドレスを取得します。次に、[0 .. 1]手段は最初からそのスライスを取得し、1つの要素だけを取得します。

これでT[]、rawWriteが1つの要素を含めて処理できるようになりました。

@safeこれが渡されない注釈を使用する場合は、マークを付ける必要があることに注意してください@trusted。またもちろん、構造体内の参照(を含むstring)は、Cの経験から確かに知っているように、データではなくバイナリポインターとして書き込まれます。しかし、あなたがそこに示した場合、あなたは大丈夫です。

編集:ところで、必要にfwrite応じて、Cから同じコードをコピーして貼り付けることもできます(foo.sizeof代わりにある場合を除くsizeof foo)。DのFileものはCの小さなラッパーでありFILE*、元のFILE *を元に戻して他の関数に渡すことができます。stream.getFP() http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html )。

1 LászlóSzerémi Aug 19 2020 at 23:55

rawWrite 配列を期待しますが、多くの回避策があります。

1つは、単一の要素配列を作成することです。

file.rawWrite([myStruct]);

もう1つは、構造体を配列にキャストすることです。bitleveldと呼ばれる私のライブラリには、と呼ばれるそのための関数がありますreinterpretAsArray。これにより、上記の構造体のチェックサムを簡単に作成することもできます。

この方法を使用した位置合わせで問題が発生することがありますので、注意してください。align構造体のプロパティを変更することで修正できます。