Scrivere una struttura binaria grezza da archiviare in D?
Sto cercando di avere un file binario che contenga diversi record binari definiti in alcuni file struct
. Tuttavia, non riesco a trovare come farlo. Guardando altri esempi, sono riuscito a scrivere string
s senza problemi, ma non struct
. Voglio solo scriverlo come farei C
con fwrite(3)
, ma nella D
versione 2.
Ecco cosa ho provato finora:
- using
stream.write(tr)
- scrive una rappresentazione leggibile dall'uomo/debug - using
stream.rawWrite(tr)
- questo suonava come quello di cui avevo bisogno, ma non riesce a compilare con:
Errore: il modello std.stdio.File.rawWrite non può dedurre la funzione dai tipi di argomento !()(TitleRecord), i candidati sono:
/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d(1132): std.stdio.File.rawWrite(T)(nel buffer T[])
- provando
rawWrite
come sopra, ma trasmettendo dati a varie cose, inoltre, non si compila mai. - anche cercando di tornare
C
confwrite
, ma non riesco ad approfondire abbastanza per ottenere il descrittore di file di cui ho bisogno.
Leggere i documenti non è stato molto utile (scrivere stringhe funziona anche per me, ma non scrivere struct
). Sono sicuro che ci deve essere un modo semplice per farlo, ma non riesco a trovarlo.... Altre domande SO non mi hanno aiutato . Io D 1.0
, potrebbe essere stato realizzato con stream.writeExact(&tr, tr.sizeof)
ma questa non è più un'opzione.
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);
}
Risposte
Per questo quell'errore sta dicendo che si aspetta un array non una struttura. Quindi un modo semplice per farlo è semplicemente affettare un puntatore e darlo a rawWrite:
stream.rawWrite((&tr)[0 .. 1]);
ottiene l' (&tr)
indirizzo, convertendo così la struttura in un puntatore. Quindi i [0 .. 1]
mezzi ne prendono una fetta dall'inizio, afferrando solo un elemento.
Quindi ora hai un T[]
file che rawWrite può gestire contenente il tuo unico elemento.
Fai attenzione se usi l' @safe
annotazione questo non passerà, dovresti contrassegnarlo @trusted
. Inoltre, ovviamente, qualsiasi riferimento all'interno della tua struct (incluso string
) verrà scritto come puntatori binari invece che come dati, come sicuramente saprai dall'esperienza C. Ma nel caso che hai mostrato lì, stai bene.
modifica: BTW potresti anche usare solo fwrite
se vuoi, copia/incolla lo stesso codice da C (tranne che è foo.sizeof
invece di sizeof foo
). La cosa D File
è solo un piccolo involucro attorno a C FILE*
e puoi recuperare il FILE * originale per passare alle altre funzioni constream.getFP()
http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html)
rawWrite
si aspetta un array, ma ci sono molte soluzioni alternative.
Uno è creare un array di elementi singoli.
file.rawWrite([myStruct]);
Un altro sta lanciando la struttura in un array. La mia libreria chiamata bitleveld ha una funzione per quella chiamata reinterpretAsArray
. Ciò semplifica anche la creazione di checksum di tali strutture.
Di tanto in tanto ho riscontrato problemi con l'allineamento utilizzando questo metodo, quindi fai attenzione. Potrebbe essere risolto modificando la align
proprietà della struttura.