Cliquer ici pour imprimer

Lecture / ecriture dans / depuis un fichier

La bibliothèque standard d'entrées/sorties du C (stdio.h pour standard input output) fournit des fonctions pour que le programme puisse lire, c'est à dire récupérer des données, et écrire, c'est à dire envoyer et/ou stocker des données, dans un fichier.

Vous connaissez déjà ces fonctions : printf pour écrire, et scanf pour lire.

En réalité, printf et scanf sont des versions proxy de fprintf et fscanf.

Extrait du résultat de la commande man 3 printf :

PRINTF(3) Linux Programmer's Manual PRINTF(3)

NAME printf, fprintf, dprintf, sprintf, snprintf, vprintf, vfprintf, vdprintf, vsprintf, vsnprintf - formatted output conversion

SYNOPSIS

   #include <stdio.h>

   int printf(const char *format, ...);
   int fprintf(FILE *stream, const char *format, ...);
   int dprintf(int fd, const char *format, ...);
   int sprintf(char *str, const char *format, ...);
   int snprintf(char *str, size_t size, const char *format, ...);

Vous voyez que la fonction fprintf a une signature très similaire à printf, elle prend un paramètre supplémentaire de type FILE* appellé stream qui représente un fichier ouvert en lecture et/ou écriture.

Un programme a systématiquement au moins trois fichiers ouverts, et peut donc utiliser trois variables gloables de type FILE* :

  • stdin : il s'agit d'une variable pointant sur la description du fichier d'entrée standard, ouvert donc en lecture
  • stdout : il s'agit d'une variable pointant sur la description du fichier de sortie standard, ouvert donc en écriture
  • stderr : il s'agit d'une variable pointant sur la description du fichier de sortie d'erreur standard, ouvert donc en écriture

Par défaut, stdin est le clavier, stdout et stderr sont tous les deux l'écran (le terminal en réalité). Ceci peut être modifié lors du lancement du programme, par exemple pour rediriger la sortie d'erreur standard d'un programme vers un fichier de log, on pourra le lancer ainsi :

$> ./mon_programme 2> error_log

Pour ouvrir d'autres fichiers, et donc obtenir plus de variables de type FILE*, il faudra utiliser la fonction fopen(). Lorsque l'on a fini d'utiliser le fichier, il faut penser à appeler la fonction fclose() pour libérer les ressources proprement.

  • lire la page de manuel de fopen()
  • quelle est la différence entre les mode r+ et w+ ? Faites un programme qui ouvre un fichier de test que vous aurez créé au préalable contenant plusieurs lignes avec le mode r+, puis le referme immédiatement. Vérifiez que le fichier n'a pas changé. Faites la même expérience avec le mode w+.
  • écrire un programme qui ouvre un fichier et écrit bonjour dedans avec fprintf.
  • Si necessaire modifiez votre programme pour que si on l'appelle plusieurs fois, le mot bonjour apparaisse plusieurs fois dans le fichier.
  • faites un programme qui ouvre un fichier en lecture et affiche son contenu en appellant successivement fscanf(...," %c",...) et printf("%c",...) dans une boucle. Comment sait on que l'on est arrivé à la fin du fichier ? Indice : lisez la section "RETURN VALUE" de la page de manuel de la fonction scanf()
  • Il existe bien sur d'autres fonctions pour lire/ecrire dans les fichiers pour répondre à des besoins spécifiques. Par exemple, il peut être pratique de lire d'un coup une ligne entière (tous les caractères jusqu'au prochain caractère \n. Pour cela vous pouvez utiliser entre autre fgets(), qui s'utilise ainsi :
    char line[MAX_LINE_SIZE];
    int taille_line;
    FILE * fichier = fopen(...);
    ...
    if(fgets(line,MAX_LINE_SIZE,fichier) == NULL){
        /* il y a une erreur de lecture */
        fprintf(stderr,"erreur de lecture du fichier"); exit(1);
    }
    ...
    fclose(fichier);

fgets met le charactère \n dans la ligne ainsi qu'un \0, permettant ainsi facilement d'afficher la ligne lue, par exemple avec printf("%s",line);

fgets est ainsi très pratique lorsqu'on connait la taille max d'une ligne. Lorsqu'on ne connait pas il y a d'autre fonction comme getline(), qui ne nous interesse pas pour le moment.

Application au mini projet

  • Ajoutez une option -i à votre programme prenant en paramètre un nom de fichier. Le programme lira alors la grille initiale dans ce fichier, ligne à ligne grace a la fonction fgets(), au lieu d'utiliser celle qui est en dur dans le code.

  • Ajoutez une option -o à votre porgramme prenant en paramètre un nom de fichier. Le programme écrira alors la grille courante à la fin du fichier lorsque l'utilisateur appuyera sur la touche s du clavier, ou lorsqu'il appuyera sur q (fin du programme).

  • Ajoutez une option -n à votre programme prenant en paramètre un entier. Si cette option est présente, et que l'option -o n'est pas presente, le programme affiche un message d'erreur. Sinon, le programme effectue directement n appels à applique(), sauvegarde le résultat dans le fichier et termine. Cela doit bien sur fonctionner aussi bien lorsque -i est présente que lorsque -i est absent.