III. Traitement d'un fichier avec une structure personnalisée▲
Dans ce premier chapitre, nous allons voir comment récupérer des informations dans un fichier avec une structure de données personnalisée soit, la structure suivante :
{
name:Franck.H
age:32
address:16 rue du General de Gaulle, 67000 Strasbourg
phone:0618325015
}
Dans ce type de structure, les accolades délimitent un bloc de données, ce qui nous permet donc de déterminer à quel moment dans le code, il faut commencer à tester et récupérer les informations. Le caractère ':' sert de séparateur entre une donnée et son nom de champ dans le fichier, on pourrait aussi mettre par exemple le caractère '=' qui est plus souvent utilisé dans ce cas de figure.
III-1. Étude algorithmique▲
Il faut pour commencer, déterminer un algorithme et donc un cheminement permettant de partir de l'ouverture d'un bloc de données jusqu'à dans notre cas, la recherche du nom d'un contact puis de récupérer ses données personnelles. Cela vaut pour tout autre programme. Voici un algorithme possible :
Ouvrir fichier
Tant que ligne <> NIL lire ligne fichier
Si caractère 0 de ligne égal à '{'
alors ouvrir bloc
sinon si bloc ouvert
Si recherche label égal à "name"
alors
Récupérer l'âge
Récupérer l'adresse
Récupérer le téléphone
Fsi
Fsi
Fin tant que
Fermer fichier
Voici une brève explication du cheminement.
- On ouvre le fichier à lire.
- On lit le fichier ligne par ligne par le biais d'une boucle Tant que(while) tant qu'on ne se trouve pas à la fin du fichier.
- On teste sur chaque ligne et tant qu'un bloc n'a pas été ouvert, si le premier caractère de la chaîne est un caractère '{'
- Si un bloc n'a pas encore été ouvert et que le premier caractère est '{', on ouvre le bloc en initialisant une variable d'état (généralement de type booléen, mais un type entier convient très bien aussi). On saute ensuite à la prochaine ligne.
- Si un bloc a déjà été ouvert, on recherche le nom du contact à retrouver en commençant par rechercher l'enregistrement portant l'identifiant « name ». Si cet identifiant a été trouvé, on compare le nom qui le suit avec le nom à retrouver.
- Si le contact a été retrouvé, on récupère une à une ses informations.
- Fermeture du fichier.
III-2. Implémentation▲
Attelons-nous maintenant à l'écriture du code en C. Il nous faut pour commencer, inclure les fichiers d'en-tête adéquats :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Nous devons maintenant préparer diverses parties pour pouvoir développer notre futur code. Nous allons plutôt utiliser des directives du préprocesseur pour définir quelques constantes symboliques ce qui permettra une plus grande facilité dans la maintenance future du code (il faut toujours penser à la maintenance du code) et aussi, rendra le code plus lisible.
#define BEGIN '{'
#define SEP ':'
#define BUF_SIZE 128
#define FILENAME "perso.txt"
#define TAG_NAME "name"
#define TAG_AGE "age"
#define TAG_ADRESS "address"
#define TAG_PHONE "phone"
Les constantes commençant par « TAG_ » sont en fait les différents champs qu'on retrouve dans un bloc de données du fichier. La constante BUF_SIZE permet de définir la limite d'un tableau de caractères donc le nombre maximum de caractères que peut contenir une chaîne après la lecture.
III-2-1. Fonction : get_infos▲
contact_infos *
get_info (
const
char
*
contact_name);
Voici la fonction principale qui va faire presque tout le travail, elle retourne une structure de type contact_infos dont voici la définition :
typedef
struct
{
char
*
name;
char
*
adress;
char
*
phone;
int
age;
}
contact_infos;
Et prend comme unique paramètre le nom du contact à retrouver. Voici l'implémentation de la fonction :
On peut revoir grâce à la numérotation en commentaire, les principales actions de l'explication du cheminement du chapitre sur l'étude algorithmique. J'ai parlé durant cette étude d'un entier qui peut servir de drapeau booléen pour déterminer l'ouverture d'un bloc de données, c'est ce que fait la variable opened. On peut voir dans la partie 5 du code, la recherche du tag name. Juste après, dans la condition if, on décale le pointeur sur la longueur du tag plus 1 caractère pour passer après le séparateur de champs ':' donc au début du nom du contact.
S'en suit la comparaison entre le nom du contact retrouvé et celui passé en argument à la fonction. Si c'est la bonne personne, on alloue dynamiquement un espace pour la structure que doit renvoyer la fonction et on la remplit par le biais d'une seconde fonction nommée get que nous allons voir juste après.
On peut apercevoir l'utilisation de constantes en troisième argument de cette seconde fonction, voici l'énumération correspondante qui servira à récupérer la suite des informations du contact :
typedef
enum
{
NAME,
AGE,
ADDRESS,
PHONE,
NB_TAG
}
contact_tags;
III-2-2. Fonction : get▲
void
get (
contact_infos *
p, FILE *
file, contact_tags tag);
Cette fonction permet de terminer la récupération des informations restantes d'un contact. Ses trois arguments sont dans l'ordre :
- un pointeur valide sur la structure que doit renvoyer la fonction get_infos ;
- un pointeur valide sur le fichier en cours de lecture ;
- le tag de type contact_tags correspondant à l'information que doit récupérer la fonction.
Voici l'implémentation de la fonction :
À chaque appel de la fonction, on lit la ligne suivante (1) du fichier. À partir de la ligne récupérée, on recherche (2) la position du séparateur de champs. Si le séparateur a été trouvé, on décale le pointeur de 1 caractère (3) pour se retrouver au début de la donnée à récupérer. On finalise enfin la chaîne (4) afin d'y ajouter un caractère de fin de chaîne en lieu et place du saut de ligne. Nous pouvons maintenant récupérer la donnée courante (5) suivant le tag passé en argument.
Vous pouvez remarquer la conversion de l'âge en entier lors de la récupération de cette donnée. Ici l'ordre de récupération des données est immuable, mais il est tout à fait possible de créer une fonction plus souple, mais qui demande davantage de temps et de lignes de code.
III-3. Code source complet▲
Voici le code source complet avec en plus le contenu du fichier perso.txt et la sortie sur la console. Dans le code vous pourrez apercevoir les fonctions décrites jusque là et une fonction contact_infos_free qui permet de libérer la mémoire allouée dynamiquement pour la structure contact_infos.
Franck.H
32
16 rue du General de Gaulle, 67000 Strasbourg
0618325015