Serializar estructuras de datos en C

Me gustaría una biblioteca C que pueda serializar mis estructuras de datos en el disco y luego cargarlas nuevamente más tarde. Debe aceptar estructuras anidadas arbitrariamente, posiblemente con referencias circulares.

Supongo que esta herramienta necesitaría un archivo de configuración que describa mis estructuras de datos. La biblioteca puede usar la generación de código, aunque estoy bastante seguro de que es posible hacer esto sin ella.

Tenga en cuenta que no estoy interesado en la portabilidad de datos. Me gustaría utilizarlo como un caché, por lo que puedo confiar en que el entorno no cambiará.

Gracias.


Resultados

Alguien sugirió Tpl, que es una biblioteca increíble, pero creo que no hace gráficos de objetos arbitrarios, como un árbol de nodos que contiene cada uno otros dos nodos.

Otro candidato es Eet , que es un proyecto del administrador de ventanas de Enlightenment. Parece interesante pero, una vez más, parece no tener la capacidad de serializar estructuras anidadas.

Echa un vistazo a tpl . De la descripción:

Tpl es una biblioteca para serializar datos de C. Los datos se almacenan en su forma binaria natural. La API es pequeña e intenta mantenerse “fuera del camino”. En comparación con el uso de XML, tpl es más rápido y fácil de usar en los progtwigs C. Tpl puede serializar muchos tipos de datos C, incluidas las estructuras.

Sé que estás pidiendo una biblioteca. Si no puede encontrar uno (:: boggle ::, ¡cree que este fue un problema resuelto!), Aquí hay un esquema para una solución:

Debería poder escribir un generador de código [1] para serializar árboles / gráficos sin preprocesamiento (en tiempo de ejecución) de manera bastante simple.

Tendrá que analizar la estructura del nodo ( typedef handling?) Y escribir los valores de los datos incluidos de manera recta, pero trate los punteros con cierto cuidado.

  • Para el puntero a otros objetos (es decir, char *name; ) que sabe que están referenciados individualmente, puede serializar los datos del objective directamente.

  • Para los objetos que pueden ser multiplicados por referencia y para otros nodos de su árbol, deberá representar la estructura del puntero. A cada objeto se le asigna un número de serialización, que es lo que se escribe en el lugar del puntero. Mantenga una estructura de traducción entre la posición actual de la memoria y el número de serialización. Al encontrar un puntero, vea si ya tiene asignado un número, de lo contrario, proporciónele uno y ponga ese objeto en cola para la serialización.

La recuperación también requiere un paso de traducción nodo # / memoria-ubicación, y puede ser más fácil hacerlo en dos pasos: regenere los nodos con los números de nodo en las ranuras del puntero (indicador incorrecto, tenga cuidado) para averiguar dónde se obtiene cada nodo poner, luego caminar la estructura de nuevo arreglando los punteros.

No sé nada sobre tpl, pero es posible que puedas aprovecharlo.


El formato de disco / red probablemente debería estar enmarcado con algún tipo de información. Necesitarás un plan para cambiar el nombre.


[1] ROOT usa este mecanismo para proporcionar soporte de serialización muy flexible en C ++.


Última adición: se me ocurre que esto no siempre es tan fácil como he indicado anteriormente. Considere la siguiente statement (artificial y mal diseñada):

 enum { mask_none = 0x00, mask_something = 0x01, mask_another = 0x02, /* ... */ mask_all = 0xff }; typedef struct mask_map { int mask_val; char *mask_name; } mask_map_t; mask_map_t mask_list[] = { {mask_something, "mask_something"}, {mask_another, "mask_another"}, /* ... */ }; struct saved_setup { char* name; /* various configuration data */ char* mask_name; /* ... */ }; 

y supongamos que struct saved_setup elementos struct saved_setup para que mask_name apunte a mask_list[foo].mask_name .

Cuando vamos a serializar los datos, ¿qué hacemos con struct saved_setup.mask_name ?

Tendrá que tener cuidado al diseñar sus estructuras de datos y / o traer alguna inteligencia específica de su caso al proceso de serialización.

Esta es mi solución. Utiliza mi propia implementación de malloc, free y mmap, llamadas al sistema munmap. Siga los códigos de ejemplo dados. Ref: http://amscata.blogspot.com/2013/02/serialize-your-memory.html

En mi enfoque, creo una matriz char como mi propio espacio RAM. Luego hay funciones para asignar la memoria y liberarlas. Después de crear la estructura de datos, al usar mmap , escribo la matriz de caracteres en un archivo.

Siempre que quiera cargarlo nuevamente en la memoria, hay una función que usa munmap para volver a poner la estructura de datos en la matriz de caracteres. Dado que tiene direcciones virtuales para sus punteros, puede reutilizar su estructura de datos. Eso significa que puede crear una estructura de datos, guardarla, cargarla, editarla nuevamente y guardarla nuevamente.

Puedes echar un vistazo a eet . Una biblioteca del proyecto de iluminación para almacenar tipos de datos C (incluidas las estructuras anidadas). Aunque casi todas las libs del proyecto de iluminación están en estado pre-alfa, eet ya se lanzó. No estoy seguro, sin embargo, si puede manejar referencias circulares. Probablemente no.

deberías pagar por gwlib. el serializador / deserializador es extenso. y hay extensas pruebas disponibles para mirar. http://gwlib.com/

Supongo que estás hablando de almacenar una estructura de gráfico, si no, entonces ignorar …

Si almacena un gráfico, personalmente creo que la mejor idea sería implementar una función que convierta su gráfico en una matriz de adyacencia. A continuación, puede realizar una función que convierta una matriz de adyacencia a su estructura de datos de gráfico.

Esto tiene tres beneficios (que pueden o no importar en su aplicación):

  • la matriz de adyacencia es una forma muy natural de crear y almacenar un gráfico
  • Puede crear una matriz de adyacencia e importarlas en sus aplicaciones
  • Puede almacenar y leer sus datos de una manera significativa.

Usé este método durante un proyecto de CS y es definitivamente cómo lo haría de nuevo.

Puede leer más sobre la matriz de adyacencia aquí: http://en.wikipedia.org/wiki/Modified_adjacency_matrix

Otra opción es Avro C , una implementación de Apache Avro en C.

En teoría, YAML debería hacer lo que quieras http://code.google.com/p/yaml-cpp/

Por favor, dígame si le funciona.

Aquí hay un ejemplo usando la biblioteca Binn (mi creación):

  binn *obj; // create a new object obj = binn_object(); // add values to it binn_object_set_int32(obj, "id", 123); binn_object_set_str(obj, "name", "Samsung Galaxy Charger"); binn_object_set_double(obj, "price", 12.50); binn_object_set_blob(obj, "picture", picptr, piclen); // send over the network send(sock, binn_ptr(obj), binn_size(obj)); // release the buffer binn_free(obj); 

Si no quiere usar cadenas como claves, puede usar un binn_map que usa números enteros como claves.

También hay soporte para listas, y todas estas estructuras se pueden anidar:

  binn *list; // create a new list list = binn_list(); // add values to it binn_list_add_int32(list, 123); binn_list_add_double(list, 2.50); // add the list to the object binn_object_set_list(obj, "items", list); // or add the object to the list binn_list_add_object(list, obj);