Supposons que l’on dispose d’un programme permettant saisir 10 entiers dans un tableau.
#include<stdio.h> int main() { int t[10], i; for(i = 0; i < 10 ; i++) { printf("Saisir un entier : "); scanf("%d", t + i); } for(i = 0 ; i < 10 ; i++) printf("%d ", t[i]); printf("\n"); return 0; }
Le problème qui se pose est que lorsque l’on sort de ce programme, les données saisies sont perdues. Si l’on souhaite les avoir à disposition pour d’une exécution ultérieure, il convient d’utiler une mémoire persistante, c’est-à-dire qui conserve les données entre deux exécutions. On utilise pour ce faire un fichier. Un fichier est une mémoire stockée de façon permanente sur un disque et à laquelle on accède avec un nom. Les données dans un fichier se présentent de façon séquentielle, et donc se lisent ou s’écrivent du début vers la fin.
Nous survolerons dans ce cours un ensemble de fonctions de
stdio.h
permettant de manier des fichiers. Pour plus détails,
il est très hautement recommandé de se reporter à la documentation.
Pour accéder au contenu d’un fichier en lecture ou en écriture, on
utilise les deux fonctions
fopen
et
fclose
.
fopen
fopen
permet, comme son nom l’indique, d’ouvrir un
fichier. Son prototype est
FILE *fopen(const char *path, const char *mode)
:
path
est une chaîne de caractère contenant le chemin
(relatif ou absolu) et le nom du fichier. Si le fichier est dans le
répertoire dans lequel s’exécute le programme, alors le nom du
fichier suffit.
mode
est une chaîne de caractère contenant
"r"
pour ouvrir le fichier en mode lecture,
"w"
en mode
écriture, etc.
FILE*
est un type permettant de référencer un fichier
ouvert,
fopen
retourne
NULL
s’il est impossible
d’ouvrir le fichier (par exemple si le nom est incorrect). La valeur
retournée devra être placée dans une variable de type
FILE*
, c’est cette valeur qui permettra par la suite
d’accéder au contenu du fichier.
fclose
fclose
sert à fermer un fichier. Son prototype est
int fclose(FILE *fp)
:
fp
est la variable de type
FILE*
permettant de
référencer le fichier à fermer.
Si l’on souhaite par exemple lire dans un fichier s’appelant
"toto.txt"
:
#include<stdio.h> int main() { FILE* f; f = fopen("toto.txt", "r"); if (f == NULL) { printf("Erreur lors de l'ouverture du fichier toto.txt\n"); return -1; } /* Lecture dans le fichier ... */ if (fclose(f)) { printf("Erreur lors de la fermeture du fichier toto.txt\n"); return -1; } return 0; }
Il existe plusieurs façons de lire dans un fichier : caractère par caractère, ligne par ligne, par paquets de caractères, etc. Chaque lecture se faisant à l’aide d’une fonction appropriée. Lors d’un traitement se faisant à partir d’une lecture dans un fichier, on appelle de façon itérée une fonction de lecture faisant avancer un curseur dans un fichier jusqu’à ce que la fin du fichier soit atteinte.
L’écriture fonctionne de façon analogue, à un détail près : il est
inutile d’écrire le caractère de fin de fichier, il est ajouté
automatiquement lors du
fclose
.
La fonction
int fgetc(FILE* stream)
retourne un caractère lu
dans le fichier
f
. Bien que le caractère lu soit un octet, il
est retourné dans un
int
. Le caractère
EOF
indique
que la fin du fichier a été atteinte. Par exemple,
#include<stdio.h> int main() { FILE* f; char c; f = fopen("toto.txt", "r"); if (f == NULL) { printf("Erreur lors de l'ouverture du fichier toto.txt\n"); return -1; } while((c = fgetc(f)) != EOF) printf("caractere lu : %c\n", c); if (fclose(f)) { printf("Erreur lors de la fermeture du fichier toto.txt\n"); return -1; } return 0; }
On écrit un caractère dans un fichier à l’aide de la fonction
int fputc(int c, FILE* stream)
.
#include<stdio.h> int main() { FILE* f; char c[8] = "Toto !\n"; int i; f = fopen("toto.txt", "w"); if (f == NULL) { printf("Erreur lors de l'ouverture du fichier toto.txt\n"); return -1; } for(i = 0 ; i < 7 ; i++) fputc(c[i], f); if (fclose(f)) { printf("Erreur lors de la fermeture du fichier toto.txt\n"); return -2; } return 0; }
Les deux fonctions
char *fgets(char *s, int size, FILE *stream)
et
int fputs(const char *s, FILE *stream)
permettent de lire et d’écrire des chaînes de caractères dans des
fichiers, voir la documentation pour plus de détails.
Les deux fonctions
size\_t fread(void *ptr, size\_t size, size\_t nmemb, FILE *stream)
et
size\_t fwrite(const void *ptr, size\_t size, size\_t nmemb, FILE *stream)
sont très utiles lorsque l’on veut sauvegarder un tableau dans un fichier, ou recopier
un fichier dans un tableau (voir la documentation pour plus de
détails). Voici tout de même deux exemples :
#include<string.h> #include<stdio.h> struct personne { char nom[30]; int age; }; int main(int argv, char** argc) { FILE* f; struct personne repertoire[4] = {{"tata", 2}, {"toto", 8}, {"titi", -1}, {"tutu", 9}}; f = fopen("toto.txt", "w"); if (f == NULL) { printf("Impossible d'ouvrir le fichier toto.txt"); return -1; } fwrite(repertoire, 4, sizeof(struct personne), f); if (fclose(f)) { printf("Impossible de fermer le fichier toto.txt"); return -2; } return 0; }
#include<string.h> #include<stdio.h> struct personne { char nom[30]; int age; }; int main(int argv, char** argc) { FILE* f; int i, n = 0; struct personne repertoire[4]; f = fopen("toto.txt", "r"); if (f == NULL) { printf("Impossible d'ouvrir le fichier toto.txt.\n"); return -1; } while(fread(repertoire + n, 1, sizeof(struct personne), f)) n++; for (i = 0 ; i < n ; i++) printf("%s %d\n", repertoire[i].nom, repertoire[i].age); if (fclose(f)) { printf("Impossible de fermer le fichier toto.txt.\n"); return -2; } return 0; }