Scrivere una struttura binaria grezza da archiviare in D?

Aug 19 2020

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 strings senza problemi, ma non struct. Voglio solo scriverlo come farei Ccon fwrite(3), ma nella Dversione 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 rawWritecome sopra, ma trasmettendo dati a varie cose, inoltre, non si compila mai.
  • anche cercando di tornare Ccon fwrite, 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

2 AdamD.Ruppe Aug 19 2020 at 21:40

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' @safeannotazione 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 fwritese vuoi, copia/incolla lo stesso codice da C (tranne che è foo.sizeofinvece 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)

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

rawWritesi 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 alignproprietà della struttura.