¿Escribir una estructura binaria sin procesar para archivar en D?

Aug 19 2020

Estoy tratando de tener un archivo binario que contiene varios registros binarios definidos en algunos archivos struct. Sin embargo, parece que no puedo encontrar cómo hacerlo. Mirando otros ejemplos, he logrado escribir strings sin problemas, pero no struct. Solo quiero escribirlo como lo haría Ccon fwrite(3), pero en la Dversión 2.

Esto es lo que he intentado hasta ahora:

  • usando stream.write(tr)- escribe representación legible por humanos/depuración
  • usando stream.rawWrite(tr): esto sonaba como lo que necesito, pero no se compila con:

Error: ¡la plantilla std.stdio.File.rawWrite no puede deducir la función de los tipos de argumento!()(TitleRecord), los candidatos son:

/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d(1132): std.stdio.File.rawWrite(T)(en el búfer T[])

  • intentando rawWritecomo arriba, pero enviando datos a varias cosas, tampoco se compila nunca.
  • incluso tratando de volver a Cwith fwrite, pero no puedo profundizar lo suficiente para obtener el descriptor de archivo que necesito.

Leer los documentos no ha sido muy útil (escribir cadenas también funciona para mí, pero no escribir struct). Estoy seguro de que debe haber una forma sencilla de hacerlo, pero no puedo encontrarla... Otras preguntas de SO no me ayudaron . I D 1.0, podría haberse logrado con stream.writeExact(&tr, tr.sizeof)pero eso ya no es una opción.

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);
}

Respuestas

2 AdamD.Ruppe Aug 19 2020 at 21:40

Para esto, ese error dice que espera una matriz, no una estructura. Entonces, una manera fácil de hacerlo es simplemente cortar un puntero y dárselo a rawWrite:

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

Obtiene la (&tr)dirección, convirtiendo así su estructura en un puntero. Luego, los [0 .. 1]medios obtienen una porción desde el principio, tomando solo un elemento.

Por lo tanto, ahora tiene un T[]elemento que rawWrite puede manejar que contiene su único elemento.

Tenga cuidado si usa la @safeanotación esto no pasará, tendrá que marcarlo @trusted. Además, por supuesto, cualquier referencia dentro de su estructura (incluido string) se escribirá como punteros binarios en lugar de datos, como seguramente sabrá por experiencia en C. Pero en el caso que mostraste allí, estás bien.

editar: Por cierto, también puede usar fwritesi lo desea, copiar/pegar el mismo código desde C (excepto que es foo.sizeofen lugar de sizeof foo). Lo D Filees solo un pequeño envoltorio alrededor de C FILE*y puede recuperar el ARCHIVO * original para pasar a las otras funciones constream.getFP() http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html)

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

rawWriteespera una matriz, pero hay muchas soluciones.

Una es crear una matriz de un solo elemento.

file.rawWrite([myStruct]);

Otro es convertir la estructura en una matriz. Mi biblioteca llamada bitleveld tiene una función para eso llamada reinterpretAsArray. Esto también facilita la creación de sumas de verificación de dichas estructuras.

De vez en cuando he encontrado problemas con la alineación usando este método, así que tenga cuidado. Podría arreglarse cambiando la alignpropiedad de la estructura.