Écrire une structure binaire brute dans un fichier en D ?
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 string
s sans problème, mais pas struct
. Je veux juste l'écrire comme je le ferais C
avec fwrite(3)
, mais dans la D
version 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
rawWrite
comme ci-dessus, mais envoyer des données à diverses choses, ne compile jamais non plus. - même en essayant de revenir
C
avecfwrite
, 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
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' @safe
annotation 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 fwrite
si vous le souhaitez, copier/coller le même code depuis C (sauf qu'il est à la foo.sizeof
place de sizeof foo
). La chose D File
n'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)
rawWrite
attend 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 align
propriété de la structure.