Question

Je développe une application de type base de données qui stocke une structure contenant :

struct Dictionary
{
    char *key;
    char *value;

    struct Dictionary *next;
};

Comme vous pouvez le voir, j'utilise une liste chaînée pour stocker des informations.Mais le problème commence lorsque l’utilisateur quitte le programme.Je veux que les informations soient stockées quelque part.Je pensais donc stocker la liste chaînée dans un fichier permanent ou temporaire en utilisant fopen, puis, lorsque l'utilisateur démarre le programme, récupérer la liste chaînée.Voici la méthode qui imprime la liste chaînée sur la console :

void PrintList()
{
    int count = 0;
    struct Dictionary *current;

    current = head;

    if (current == NULL)
    {
            printf("\nThe list is empty!");
        return;
    }

    printf("    Key \t  Value\n");
    printf("  ======== \t ========\n");

    while (current != NULL)
    {
        count++;
        printf("%d.  %s \t %s\n", count, current->key, current->value);
        current = current->next;
    }
}

Je pense donc modifier cette méthode pour imprimer les informations via fprintf au lieu de printf, puis le programme obtiendrait simplement les informations du fichier.Quelqu'un pourrait-il m'aider sur la façon de lire et d'écrire dans ce fichier ?De quel type de fichier doit-il s'agir, temporaire ou régulier ?Comment dois-je formater le fichier (comme si je pensais avoir d'abord la clé, puis la valeur, puis un caractère de nouvelle ligne) ?

Était-ce utile?

La solution

Le fichier devrait probablement être régulier. Un fichier temporaire n'est pas garanti d'être là la prochaine fois que démarrer votre application. En outre, le format, il semble bien pour l'homme, pas si bien pour les machines. Je vous recommande de créer soit votre propre format de fichier binaire ou en utilisant XML (ou JSON peut-être?). Vous pouvez formater probablement assez facilement comme

key1\0value1\0key2\0value2\0....

Je vais écrire un exemple rapide est le code psuedoish:

//To write...
Dictionary *this=begin_list;
while(this!=null){
  for(i=0;i<strlen(this->key);i++){
    write_byte(this->key[i]);
  }
  for(i=0;i<strlen(this->value);i++){
    write_byte(this->value[i]);
  }
  this=this->next;
}

//to read...
Dictionary *prev;
Dictionary *this;
char *buffer;
while(!eof){
  buffer=malloc(MAX_STRING_LEN);
  int i=0;
  this=malloc(sizeof(Dictionary)
  while(i<MAX_STRING_LEN){ //note no error checking
    buffer[i]=read_byte();
    if(buffer[i]==0){
      break;
    }
  }
  this->key=buffer;
  buffer=malloc(MAX_STRING_LEN)
  while(i<MAX_STRING_LEN){ //note no error checking
    buffer[i]=read_byte();
    if(buffer[i]==0){
      break; 
    }
  }
  this->value=buffer;
  if(prev!=null){
    prev->next=this;
  }
  this->next=null;
  prev=this;
}

Je sais qu'il est un mauvais exemple. Je pense que scanf ou similaire peuvent rendre le travail plus facile une tonne, mais mes compétences en C sont rouiller.

Autres conseils

Le problème fondamental est que les pointeurs ne se traduisent pas en stockage externe.Il n'y a aucune garantie que lorsque votre programme s'exécutera à nouveau, il aura les mêmes plages de mémoire (adresses).Compte tenu de ce principe, il existe des méthodes alternatives pour stocker vos données.

Processus pour les données persistantes :
1.Utilisez une base de données, petite ou grande.
2.Convertissez vos données en texte ASCII dans un format numérisable.
3.Utiliser des enregistrements binaires de longueur fixe
4.Utiliser des enregistrements binaires de taille variable
5.Implémentez une structure de données de dictionnaire en utilisant des décalages de fichiers au lieu de pointeurs.

Utiliser une base de données
Laissez une application professionnelle (testée et fonctionnelle) gérer vos données.Cela vous permet de vous concentrer sur l'utilisation des données plutôt que sur le stockage et la récupération.

Convertir en un format numérisable
L'idée ici est d'écrire les données dans le fichier dans un format facile à récupérer et à gérer.Les exemples incluent les valeurs séparées par des virgules (CSV), XML et INI.Cela nécessite du code de votre part pour lire et écrire les données.Il existe des bibliothèques pour vous aider.

Utiliser des enregistrements binaires de longueur fixe
Avec des enregistrements de longueur fixe, les données sont lues à partir du fichier et insérées dans votre dictionnaire.Les fichiers binaires sont très efficaces en termes de transfert de données, mais ne sont pas très portables, en particulier lorsque les versions du système d'exploitation changent, les plates-formes changent ou les versions du compilateur changent.Il peut y avoir une perte d'espace pour les enregistrements de texte.

Utiliser des enregistrements binaires de taille variable
Cette technique permet d'économiser de l'espace mais augmente le temps de traitement.Chaque enregistrement doit être traité afin de trouver l'emplacement du suivant.L'accès aléatoire aux enregistrements est difficile.Sinon similaire aux enregistrements binaires de longueur fixe.

Implémenter une structure de données de dictionnaire dans le fichier
Même algorithme que votre structure de données basée sur la mémoire, sauf qu'il utilise des décalages de fichiers au lieu de pointeurs.Les nouveaux enregistrements peuvent être ajoutés à la fin du fichier.Récupérer les entrées supprimées est difficile et entraînera une fragmentation.La fragmentation peut être résolue en écrivant un nouveau fichier.Si vous faites autant d’efforts, vous pouvez aussi bien utiliser une application de base de données existante.

Une façon vous pouvez lire ou écrire dans le fichier en utilisant fReopen comme ceci: freopen ( « file.out », « poids », stdout), alors vous de printf ira à la file.out et vous ne devez modifier le code beaucoup.

Vous pouvez stocker les informations en texte clair, mais je pense vraiment que la meilleure façon de le faire est enregistrer les informations dans un fichier binaire. Vous pouvez consulter plus sur cette information de recherche sur les fread et fwrite.

Voici une façon de résoudre le problème.

Créer une structure de données pour vos éléments de liste comme ceci:

struct DictionaryArchive {
    char key[MAX_KEY_LENGTH];
    char value[MAX_VALUE_LENGTH];
    int next;
};

Vous devrez déterminer les valeurs de MAX_KEY_LENGTH et MAX_VALUE_LENGTH selon les données que vous nous attendrons.

Maintenant, convertir votre liste chaînée dans un tableau de ces structures. Au lieu de stocker un pointeur pour localiser l'élément suivant, vous stockerez l'index du tableau de l'élément suivant. Ceci convertit votre liste dans un format où chaque élément est une taille prévisible votre liste complète est une durée consécutive de mémoire. Maintenant, vous pouvez fwrite ce tableau dans un fichier binaire pour archiver et fread en arrière sur la restaurer.

Une alternative beaucoup plus efficace l'espace à l'aide de tableaux de char taille fixe ci-dessus est de définir la place d'un format de fichier personnalisé au lieu d'utiliser des structures statiques. Pour votre cas, vous pouvez utiliser un format de fichier comme celui-ci pour stocker vos données de manière récupérable:

  • La liste est écrite dans le fichier dans l'ordre, en commençant par la tête et en suivant les pointeurs de next à la queue
  • Chaque élément de la liste sera stockée en utilisant quatre champs de données dans l'ordre suivant:
    1. entier de 16 bits, key_length
    2. du tableau de caractères à 8 bits avec des éléments de key_length, key_data
    3. entier de 16 bits, value_length
    4. du tableau de caractères à 8 bits avec des éléments de value_length, value_data

Maintenant, vous pouvez marcher la liste, le dumping vos données au noeud de fichier par nœud. Pour reconstituent vos données, lisez le fichier binaire, générer de nouveaux éléments de struct Dictionary pour chaque entrée, et les relier entre eux dans l'ordre où ils apparaissent dans le fichier.

Votre code pour écrire les données dans le fichier de données ressemblerait à quelque chose comme ça (non testé, à des fins d'illustration seulement):

FILE* fd;
size_t len;
struct Dictionary* pDict = list_head;
fd = fopen("output_file.dat", "w");

// Walk through the list, storing each node
while (pDict != NULL) {
    // Store key
    len = strlen(pDict->key);
    fwrite(&len, sizeof(len), 1, fd);
    fwrite(pDict->key, len, sizeof(char), fd);

    // Store value
    len = strlen(pDict->value);
    fwrite(&len, sizeof(len), 1, fd);
    fwrite(pDict->value, len, sizeof(char), fd);

    // Move to next list node
    pDict = pDict->next;
};

fclose(fd);

Votre code pour lire les données out serait très similaire (lire au lieu d'écrire et de créer un nouvel objet struct Dictionary pour chaque itération de la boucle).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top