Écrire une structure binaire brute dans un fichier en D ?

Aug 19 2020

J'essaie d'avoir un fichier binaire qui contient plusieurs enregistrements binaires définis dans certains fichiers struct. Cependant, je ne semble pas trouver comment le faire. En regardant d'autres exemples, j'ai réussi à écrire strings sans problème, mais pas struct. Je veux juste l'écrire comme je le ferais Cavec fwrite(3), mais dans la Dversion 2.

Voici ce que j'ai essayé jusqu'à présent :

  • using stream.write(tr)- écrit une représentation lisible par l'homme/débogage
  • using stream.rawWrite(tr)- cela ressemblait à ce dont j'avais besoin, mais ne parvient pas à compiler avec:

Erreur : le modèle std.stdio.File.rawWrite ne peut pas déduire la fonction des types d'argument !())(TitleRecord), les candidats sont :

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

  • essayer rawWritecomme ci-dessus, mais envoyer des données à diverses choses, ne compile jamais non plus.
  • même en essayant de revenir Cavec fwrite, mais je n'arrive pas à aller assez loin pour obtenir le descripteur de fichier dont j'ai besoin.

La lecture de la documentation n'a pas été très utile (l'écriture de chaînes fonctionne aussi pour moi, mais pas l'écriture struct). Je suis sûr qu'il doit y avoir un moyen simple de le faire, mais je ne suis pas en mesure de le trouver .... D'autres questions SO ne m'ont pas aidé . I D 1.0, cela aurait pu être fait avec stream.writeExact(&tr, tr.sizeof)mais ce n'est plus une 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);
}

Réponses

2 AdamD.Ruppe Aug 19 2020 at 21:40

Pour cela, cette erreur indique qu'elle attend un tableau et non une structure. Donc, un moyen simple de le faire est simplement de découper un pointeur et de le donner à rawWrite :

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

Le (&tr)obtient l'adresse, convertissant ainsi votre structure en pointeur. Ensuite, les [0 .. 1]moyens en obtiennent une tranche depuis le début, en ne saisissant qu'un élément.

Ainsi, vous avez maintenant un T[]que rawWrite peut gérer contenant votre seul élément.

Soyez averti si vous utilisez l' @safeannotation cela ne passera pas, vous devrez le marquer @trusted. De plus, bien sûr, toutes les références à l'intérieur de votre structure (y compris string) seront écrites sous forme de pointeurs binaires au lieu de données, comme vous le savez sûrement par expérience C. Mais dans le cas que vous avez montré là, tout va bien.

edit: BTW vous pouvez également utiliser fwritesi vous le souhaitez, copier/coller le même code depuis C (sauf qu'il est à la foo.sizeofplace de sizeof foo). La chose D Filen'est qu'un petit wrapper autour de C FILE*et vous pouvez récupérer le FILE * d'origine pour le passer aux autres fonctions avecstream.getFP() http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html)

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

rawWriteattend un tableau, mais il existe de nombreuses solutions de contournement.

L'une consiste à créer un seul tableau d'éléments.

file.rawWrite([myStruct]);

Un autre consiste à lancer la structure dans un tableau. Ma bibliothèque appelée bitleveld a une fonction pour cela appelée reinterpretAsArray. Cela facilite également la création de sommes de contrôle desdites structures.

De temps en temps, j'ai rencontré des problèmes d'alignement en utilisant cette méthode, alors soyez prudent. Peut être corrigé en modifiant la alignpropriété de la structure.