2010-10-12 4 views
6

J'ai une partie de ma mémoire que je veux sauvegarder dans un fichier. Une raison est de sauvegarder l'information quelque part, et une autre est de la relire quand mon programme redémarre.Décharger de la mémoire dans le fichier

Quelle est la bonne façon de faire cela?

Ma première pensée a été:

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

Puis-je écrire tout comme des personnages? Et puis utilisez quelque chose comme ça pour le restaurer en mémoire.

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

Est-ce que mes « datastructures » survivre « charachters », ou dois-je écrire dans une sorte de binaire/hexa données en mode? Ou est-ce une manière standard de le faire?

+4

Contient-elle des pointeurs? – ruslik

+0

Oui, il contient des pointeurs. Mais je pense que je peux reprogrammer certaines parties pour l'éviter. Merci pour toutes les réponses, ça m'a beaucoup aidé! – kristus

Répondre

9

Ce problème est appelé « serializing » et peut aller de trivial vraiment compliqué. Si votre structure de données est autonome, par exemple un groupe de pixels dans un tableau et que vous connaissez les dimensions du tableau, vous pouvez simplement vider les données et les relire.

Si vous avez par exemple des listes liées, ou des pointeurs de toutes sortes, dans vos données, ces pointeurs ne pointeront vers rien de valable une fois que vous les aurez relues. C'est là qu'une approche plus formelle de la sérialisation commence à avoir du sens.

Cela peut aller de l'enregistrement au format de fichier, à l'utilisation de bases de données, à la conversion au format XML ou autre format hiérarchique, etc. Qu'est-ce qu'une solution OK dépend complètement de ce type de données que vous avez, et quels types d'opérations que vous faites dessus plus comment souvent vous prévoyez d'écrire, puis relire à partir du disque. (.. Réseau ou tout ce que vous faites)

Si ce que vous avez est un blob trivial de données, et vous voulez juste écrire la façon la plus simple possible, utilisez fwrite():

fwrite(my_pointer, MEMORY_SIZE, 1, fp); 

et puis fread() pour lire les données de retour. Voir aussi une connexe (plus ou moins liée selon l'évolution de vos besoins) serializing question on StackOverflow.

Correct serialization résout également the problems that appear lorsque différents types de processeurs sont supposés être capables de lire les données les uns des autres. Une sérialisation correcte en C est beaucoup plus compliquée que dans d'autres langues. En Lisp par exemple, toutes les données et le code sont déjà sérialisés. En Java, il existe des méthodes pour vous aider à sérialiser vos données.Les propriétés de C qui en font un langage approprié pour la haute performance et la programmation des systèmes rendent également plus difficile à utiliser pour d'autres choses.

+1

Je pense que je vais reprogrammer un peu pour le rendre plus simple et plus facile à sauvegarder/restaurer. – kristus

2

Si vous utilisez un système de style Unixy, memmap et memcpy peuvent vous donner une solution soignée.

2

Vous pouvez utiliser

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

.

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

Est-ce que mes « datastructures » survivre « charachters », ou dois-je écrire dans une sorte de binaire/hexa données en mode? Ou est-ce une manière standard de le faire?

lorsque vous ouvrez le fichier - utilisez le caractère « b » en « mode » PARAM

1

La meilleure façon d'y parvenir est d'utiliser une bibliothèque de sérialisation. Que vous ayez vraiment besoin de cela dépend de la complexité de vos données. Si les données que vous avez besoin d'écrire ne contiennent aucun pointeur, vous pouvez simplement utiliser fwrite pour écrire les données et fread pour le relire. Assurez-vous simplement que vous avez ouvert le fichier avec les données en binaire mode. Si les données à sérialiser contiennent des pointeurs, il vaut mieux utiliser une bibliothèque externe écrite à cette fin, car la bibliothèque s'assurera que les pointeurs sont écrits de telle sorte qu'ils puissent être correctement reconstruits plus tard.

2

Tant que les données que vous videz ne contiennent aucun pointeur, il suffit de les vider comme cela fonctionnera. (CONSEIL: utilisez les appels qui peuvent écrire de longues séquences de données en une seule fois pour réduire le temps.) La seule chose à surveiller est de savoir si vous écrivez des entiers ou des nombres à virgule flottante et de les lire sur une machine avec une architecture différente (par exemple, big endian au lieu de little endian). Cela pourrait ou ne pas être une préoccupation pour vous. Mais si vous avez des pointeurs à l'intérieur, vous avez un problème. Le problème est que vous ne pouvez pas (bien, ne peut pas facilement) garantir que vous récupérerez les données à la même position dans l'espace mémoire virtuel du processus de réception. De plus, si vous avez des données qui ont des pointeurs vers des choses que vous n'enregistrez pas (par exemple, un FILE* errant) alors vous devez penser à ce qu'il faut faire pour resynthétiser un remplacement valide à ce moment-là. Une telle sérialisation est profondément non-triviale, et nécessite l'écriture d'un code qui connaît exactement ce que vous enregistrez et chargez.

Il existe un moyen de simplifier un peu la sérialisation lorsque vous avez seulement des pointeurs dans les données contiguës qui sont sauvegardées et que vous allez toujours les restaurer sur la même architecture. Dump la mémoire comme avant, mais mettre un descripteur de préfixe sur ce qui dit au moins la longueur des données et le nombre de pointeurs à l'intérieur, puis enregistrer (à la fin) une table d'où exactement (comme offsets dans les données) le les pointeurs sont et où le début de toutes les données était. Vous pouvez ensuite restaurer en lisant les données et en exécutant l'arithmétique d'adresse pour corriger tous les pointeurs, c'est-à-dire, vous pouvez déterminer quel décalage par rapport au début des données originales pointées - char*, pas le type original - et assurez-vous qu'ils pointent vers le même décalage par rapport à l'adresse de l'ensemble des données après rechargement. C'est un hack un peu grossier et formellement pas la chose la plus portable jamais, mais dans les contraintes décrites au début de ce paragraphe, je m'attendrais à ce que cela fonctionne. Cependant, vous aurez également un format de sérialisation vraiment non portable; ne comptez pas dessus à tout pour toute sorte d'utilisation archivistique persistante!

Questions connexes