Dumping de memoria a archivo

Tengo una parte de mi memoria que quiero volcar en un archivo. Una razón es guardar la información en algún lugar, y otra es leerla nuevamente cuando mi progtwig se reinicia.

¿Cuál es la forma correcta de hacer esto?

Mi primer pensamiento fue:

char* start = my_pointer; int i; for (i = 0; i < MEMORY_SIZE; i++) { // write *start to file start++; } 

¿Puedo escribirlo todo como personajes? Y luego usa algo como esto para restaurarlo en la memoria.

 //loop *my_pointer = fgetc(f); my_pointer++; 

¿Mis “estructuras de datos” sobrevivirán como “personajes”, o tengo que escribirlas en algún tipo de modo de datos binario / hexadecimal? ¿O es una forma estándar de hacer esto?

Este problema se denomina ” serialización ” y puede ir desde trivial hasta realmente complicado. Si su estructura de datos es autónoma, por ejemplo, un grupo de píxeles en una matriz y conoce las dimensiones de la matriz, puede volcar los datos y luego volver a leerlos.

Si tiene, por ejemplo, listas vinculadas, o punteros de cualquier tipo, en sus datos, esos punteros no apuntarán a nada válido una vez que los vuelva a leer. Aquí es donde un enfoque más formal para la serialización comienza a tener sentido.

Esto puede ir desde guardar como formatos de archivo, usar bases de datos, convertir a XML u otro formato jerárquico y así sucesivamente. Lo que es una solución correcta depende completamente del tipo de datos que tiene y del tipo de operaciones que realiza, además de la frecuencia con la que planea escribir y luego leer desde el disco. (O red. O lo que sea que estés haciendo.)

Si lo que tienes es una masa trivial de datos, y solo quieres escribirlos de la manera más simple posible, usa fwrite () :

 fwrite(my_pointer, MEMORY_SIZE, 1, fp); 

y luego fread () para volver a leer los datos. También vea una pregunta de serialización relacionada (más o menos relacionada dependiendo de qué tan avanzadas sean sus necesidades) en StackOverflow .

La serialización adecuada también resuelve los problemas que aparecen cuando se supone que diferentes tipos de CPU pueden leer datos entre sí. La serialización adecuada en C es mucho más complicada que en otros idiomas. En Lisp, por ejemplo, todos los datos y el código ya están serializados. En Java, existen métodos para ayudarlo a serializar sus datos. Las propiedades de C que lo convierten en un lenguaje adecuado para el alto rendimiento y la progtwigción de sistemas también lo hacen más difícil de usar para otras cosas.

Si estás en un sistema de estilo unixy, memmap y memcpy pueden darte una solución ordenada.

Puedes usar

 size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream ); 

función.

 ptr - pointer to you memory segment. size - size of memory to write. stream - file you writing to. 

¿Mis “estructuras de datos” sobrevivirán como “personajes”, o tengo que escribirlas en algún tipo de modo de datos binario / hexadecimal? ¿O es una forma estándar de hacer esto?

cuando abra el archivo, use el carácter ‘b’ en el modo “modo”

Siempre y cuando los datos que está descargando no contengan punteros, simplemente el vaciarlos así funcionará. (SUGERENCIA: utilice las llamadas que pueden escribir largas secuencias de datos de una vez para reducir el tiempo). Lo único que debe tener en cuenta es si escribe números enteros o de coma flotante y los vuelve a leer en una máquina con una architecture diferente (por ejemplo, big endian en lugar de little endian). Eso podría o no ser una preocupación para ti.

Pero si tienes punteros dentro, tienes un problema. El problema es que no puede (bueno, no es fácil) garantizar que obtendrá los datos cargados de nuevo en la misma posición en el espacio de memoria virtual del proceso de recepción. Lo que es más, si tiene datos que tienen punteros a cosas que no está guardando (por ejemplo, un FILE* extraviado FILE* ), entonces debe pensar qué hacer para volver a sintetizar un reemplazo válido en ese momento. Dicha serialización es profundamente no trivial y requiere escribir código que tenga conocimiento de lo que está guardando y cargando.

Hay una manera de simplificar un poco la serialización cuando solo tiene punteros dentro de los datos contiguos que se guardan y siempre se restaurarán en la misma architecture. Descargue la memoria como antes, pero coloque un descriptor de prefijo que diga al menos la longitud de los datos y el número de punteros dentro, luego también guarde (al final) una tabla de donde exactamente (como compensaciones dentro de los datos) la Los punteros son y donde estaba el inicio de todos los datos. Luego puede restaurar al leer los datos y realizar una aritmética de direcciones para corregir todos los punteros, es decir, puede calcular qué desplazamiento relativo al inicio de los datos originales a los que apuntaban, como un char* , no el tipo original. y asegúrese de que apunten al mismo desplazamiento en relación con la dirección de todos los datos después de la recarga. Este es un truco un tanto grave y formalmente no es lo más portátil, pero dentro de las restricciones descritas al principio de este párrafo, espero que funcione. Sin embargo, también tendrá un formato de serialización realmente no portátil; ¡No cuente con ello para ningún tipo de uso persistente de archivos!

La forma correcta de hacerlo es utilizar una biblioteca de serialización.

Si realmente necesita eso depende de la complejidad de sus datos. Si los datos que necesita escribir no contienen punteros de ningún tipo, entonces podría usar fwrite para escribir los datos y leerlos nuevamente. Solo asegúrese de haber abierto el archivo con los datos en binario modo.

Si los datos a serializar contienen punteros, es mucho mejor utilizar una biblioteca externa escrita para este propósito, ya que la biblioteca garantizará que los punteros se escriban de tal manera que puedan reconstruirse correctamente más adelante.