I'm trying to have a binary file which contains several binary records defined in some struct
. However, I do cannot seem to find how to do it. Looking at other examples, I've managed to write string
s without problems, but not struct
. I just want to write it like I would in C
with fwrite(3)
, but in D
version 2.
Here is what I've tried so far:
stream.write(tr)
- writes human readable/debug representationstream.rawWrite(tr)
- this sounded like what I need, but fails to compile with:Error: template std.stdio.File.rawWrite cannot deduce function from argument types !()(TitleRecord), candidates are:
/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d(1132): std.stdio.File.rawWrite(T)(in T[] buffer)
rawWrite
as above, but casting data to various things, also never compiles.C
with fwrite
, but can't get deep enough to get file descriptor I need.Reading the docs has not been very helpful (writing strings works for me too, but not writing struct
). I'm sure there must be simple way to do it, but I'm not able to find it.... Other SO questions did not help me. I D 1.0
, it might have been accomplished with stream.writeExact(&tr, tr.sizeof)
but that is no longer an option.
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);
}
For this that error is saying it expects an array not a struct. So one easy way to do it is to simply slice a pointer and give that to rawWrite:
stream.rawWrite((&tr)[0 .. 1]);
The (&tr)
gets the address, thus converting your struct to a pointer. Then the [0 .. 1]
means get a slice of it from the beginning, grabbing just one element.
Thus you now have a T[]
that rawWrite can handle containing your one element.
Be warned if you use the @safe
annotation this will not pass, you'd have to mark it @trusted
. Also of course any references inside your struct (including string
) will be written as binary pointers instead of data as you surely know from C experience. But in the case you showed there you're fine.
edit: BTW you could also just use fwrite
if you like, copy/pasting the same code over from C (except it is foo.sizeof
instead of sizeof foo
). The D File
thing is just a small wrapper around C's FILE*
and you can get the original FILE* back out to pass to the other functions with stream.getFP()
http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html )