Pregunta

Tengo una función C que escribe algunos datos a un archivo de texto. Los datos consisten en coma flotante, enteros y cadenas. se ve algo como esto:

writeAsTextFile(  mystruct_t* myStructWithIntsFloatsAndStrings , const char* fileName);

para hacer esto que el uso de las llamadas fprintf;

Ahora me gustaría escribir los mismos datos, pero como binario. Podría escribir un segundo writeAsBinaryFile función y el uso de las llamadas a fwrite lugar. Pero entonces cada vez que voy a hacer que cambie el diseño de mystruct_t voy a tener que modificar tanto writeAsTextFile y writeAsBinaryFile. Y por supuesto la correspondiente readAsTextFile y readAsBinaryFile. Además de esto esto aumentará codesize. Por lo tanto me gustaría tener una sola función genérica con un argumento bin-o-texto que se vería así:

writeToFile( mystruct_t* myStructWithIntsFloatsAndStrings , const char* fileName, myEnumType_t eOption)

donde opción sería una enumeración Ebin = 0 y eTxt = 1 por ejemplo. Dependiendo de eOption, la función sería escribir datos binarios o de texto.

No estoy seguro de lo que sería la mejor manera de lograr esto. ¿Debo usar fwrite también para la escritura como texto, debo tratar de usar macros? (He visto el uso de la directiva ## en alguna parte, pero nunca utilizado), o / IFS declaraciones en todas partes tengo que escribir en el archivo? O tendría que escribir una función genérica como myWriteFunction( void *data, char const type, myEnumType_t eOption)

que sería llamado por WriteToFile?

No estoy muy familiarizado con el uso fread / fwrite y macros por lo que cualquier mejores prácticas comentarios, ideas, etc es bienvenido,

Gracias

Baba

¿Fue útil?

Solución

Se puede crear un par de funciones para la escritura de varios tipos de datos en su struct:

writeInt(File *f, myEnumType_t eOption, int data);
writeFloat(File *f, myEnumType_t eOption, float data);
writeFloatArray(File *f, myEnumType_t eOption, float *data, size_t n_data);

.. entonces la prueba-o-texto binario se oculta en cada uno de esos. Su principal función struct-escritura se vería así (con la comprobación de errores omite):

writeToFile(mystruct_t *myStruct, const char *fileName, myEnumType_t eOption)
{
    const char *fmode = eOption == EOPT_BIN ? "wb" : "w";
    FILE *f = fopen(filename, fmode);

    writeInt(f, eOption, myStruct->a);
    writeInt(f, eOption, myStruct->b);
    writeFloatArray(f, eOption, myStruct->values, myStruct->n_values);
    /* ... */
 }

Así que un cambio en el diseño de la estructura sólo tiene que cambiar un solo lugar.

También puede implementar diferentes funciones de escritura para diferentes a nivel de aplicación "tipos" -. Por ejemplo writeTemperature() podría ser distinto de un writeFloat() genérica

Otros consejos

Por su situación, sólo tiene que hacer una función de envoltura:

writeToFile(...,bool isBinary) {
  if (isBinary) {
    // write as binary file
  } else {
    // write as text file
  }
}

En lo que MACROS van, sólo son útiles si desea que todas las operaciones deberán ser de texto o binario:

#ifdef __BINARY
#define WriteToFile(a,b,c,d,e) WriteToBinary(a,b,c,d,e)
#else
#define WriteToFile(a,b,c,d,e) WriteToText(a,b,c,d,e)
#endif

Esto se utiliza en la API de Windows para cambiar entre las funciones ASCII y funciones de caracteres anchos.

Por cierto: Si su estructura contiene * CHAR o std :: string, entonces no se copiará el contenido de la cadena, al igual que de la dirección. Esto se aplica a cualquier otro aswell punteros, como int * o un std :: vector.

En primer lugar, no combine las funciones, hay posibilidades concretas de ahorro no.

En segundo lugar, usted va a tener que escribir una nueva escritura como la función de texto cada vez que utilice la estructura, no hay forma de evitar eso (excepto alguna biblioteca de serialización no estándar).

En tercer lugar, siempre y cuando no cambie el orden de los miembros de la estructura, y sólo añadir nuevos miembros a la final de la estructura, que nunca tenga que escribir un nuevo escritor binario o lector. Con el fin de lograr esto, usted debe escribir el tamaño de la estructura para el archivo y luego escribir la estructura para el archivo.

De esta manera, su función de lectura leerá el tamaño de la estructura (cuando se escribió) y sabrá cuántos bytes a leer. Si cambia su estructura, su programa será capaz de leer las partes de la estructura de la versión antigua, y los nuevos miembros al final de la estructura será inicializado.

Editar

Escribir una estructura con punteros escribirá el valor del puntero. Tienes que ser muy cuidadoso cuando se lee la estructura, porque el puntero apuntará a una paz esencialmente aleatoria de memory.b

Si desea mantener las relaciones entre las estructuras que tendrá que venir con su propio mecanismo. Esto varía en dificultad, que tendrá que llegar a algún orden predefinido para la escritura de las estructuras, y la reconstrucción de todos los punteros cuando se lee la estructura.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top