Lire et écrire des fichiers

Approfondir : Lire et écrire des fichiers

Un fichier permet de conserver des données après la fin du programme. La bibliothèque standard utilise des flux manipulés avec FILE*. On doit distinguer le nom du fichier, le flux ouvert, les opérations effectuées et les erreurs possibles.

Ouvrir dans le bon mode

fopen renvoie NULL en cas d’échec. Le mode r ouvre un fichier existant en lecture ; w crée ou tronque un fichier en écriture ; a ajoute en fin de fichier. Les modes contenant + permettent lecture et écriture avec des règles de transition supplémentaires. Pour commencer, fermer puis rouvrir le fichier sépare clairement les deux phases.

Lire un caractère ou une ligne

fgetc renvoie un int pour pouvoir représenter tous les caractères possibles et la valeur spéciale EOF. Stocker ce résultat dans char avant de tester EOF peut perdre la distinction. fgets lit une portion bornée de ligne dans un tableau ; une lecture réussie garantit le nul final, mais une longue ligne peut demander plusieurs appels.

Tester l’opération plutôt que prédire la fin

La boucle correcte teste directement le résultat de lecture, par exemple while ((c=fgetc(f)) != EOF). Une boucle fondée seulement sur !feof(f) risque un tour supplémentaire avec une donnée périmée : l’indicateur de fin n’est posé qu’après une lecture qui rencontre la fin. Après la boucle, ferror distingue une erreur d’une fin normale.

Écrire et fermer

Les fonctions d’écriture peuvent échouer, et une partie des données peut rester en tampon jusqu’à la fermeture. Vérifier le retour des écritures et celui de fclose lorsqu’une erreur doit être signalée. Une fermeture réussie n’est pas à elle seule une garantie de conservation physique face à toute panne ; il s’agit ici de la gestion du flux standard, pas d’un protocole de sauvegarde transactionnelle.

Choisir un format de données

Un fichier texte avec une ligne par donnée est facile à lire et à contrôler. Définir le séparateur, le nombre de champs et les unités avant d’écrire un lecteur. Pour un fichier binaire, décider explicitement de la représentation et des tailles ; copier directement les octets d’une structure n’assure pas un échange portable entre machines.

Fichiers : compter les fins de ligne

#include <stdio.h>
int main(void) {
    FILE *f = fopen("flux-demo.tmp", "w+b");
    if (f == NULL) { puts("Ouverture impossible."); return 1; }
    if (fputs("alpha\nbeta\n", f) == EOF ||
        fseek(f, 0L, SEEK_SET) != 0) {
        fclose(f);
        return 1;
    }
    int c, lignes = 0;
    puts("Contenu :");
    while ((c = fgetc(f)) != EOF) {
        putchar(c);
        if (c == '\n') { ++lignes; }
    }
    if (ferror(f)) { fclose(f); return 1; }
    if (fclose(f) != 0) { return 1; }
    if (remove("flux-demo.tmp") != 0) { return 1; }
    printf("Fins de ligne = %d\n", lignes);
    return 0;
}
Suivre le programme : Fichiers, compter les fins de ligne
Instruction ou étapeExplication
fopen en w+bCrée le fichier flux-demo.tmp dans le dossier d’essai ; ce nom est réservé à la démonstration. Le fichier est supprimé après fermeture.
fputs puis fseekÉcrit deux lignes et repositionne le flux au début avant la lecture.
fgetc dans un intChaque caractère est affiché et les sauts de ligne sont comptés.
ferror puis fcloseLa fin normale est distinguée d’une erreur de lecture ; le flux est ensuite fermé.

Sortie écran : essai 1

Le texte de démonstration contient exactement deux caractères de fin de ligne.

Contenu :
alpha
beta
Fins de ligne = 2

Fichiers : écrire et relire un fichier nommé

#include <stdio.h>
int main(void) {
    const char *nom = "notes-demo.txt";
    FILE *f = fopen(nom, "w");
    if (f == NULL) { return 1; }
    if (fprintf(f, "%d\n%d\n", 12, 15) < 0) { fclose(f); return 1; }
    if (fclose(f) != 0) { return 1; }
    f = fopen(nom, "r");
    if (f == NULL) { return 1; }
    int valeur, somme = 0, nombre = 0;
    while (fscanf(f, "%d", &valeur) == 1) {
        somme += valeur;
        ++nombre;
    }
    if (ferror(f) || !feof(f)) { fclose(f); return 1; }
    if (fclose(f) != 0) { return 1; }
    printf("Notes = %d\nSomme = %d\n", nombre, somme);
    return 0;
}
Suivre le programme : Fichiers, écrire et relire un fichier nommé
Instruction ou étapeExplication
Mode wCrée ou remplace notes-demo.txt dans le dossier courant. Employer ce nom de démonstration dans un dossier d’essai.
Deux valeurs connuesLes entiers 12 et 15 sont écrits sur deux lignes.
Fermeture et réouvertureLe flux d’écriture est fermé avant l’ouverture en lecture.
fscanf==1On ne cumule que les lectures réussies. Le fichier est créé par ce même programme avec de petits entiers représentables.
Contrôle finalUne fin normale donne deux notes et une somme de 27.

Sortie écran : essai 1

Le programme produit lui-même le petit fichier qu’il lit ensuite.

Notes = 2
Somme = 27

S’entraîner et vérifier

Exercice 1. Pourquoi compter les sauts de ligne n’est-il pas toujours compter les lignes de texte ?

Voir la correctionMasquer la correction

Un dernier fragment peut ne pas se terminer par un saut de ligne. Le premier programme annonce précisément un nombre de fins de ligne ; pour compter aussi un fragment final, mémoriser si le dernier caractère lu n’était pas '\n'.

Exercice 2. Que se passe-t-il si une lettre remplace la deuxième note dans un fichier externe ?

Voir la correctionMasquer la correction

fscanf ne réalise pas la conversion et la boucle s’arrête. Le contrôle de fin détecte que le flux n’est pas arrivé normalement à EOF. Pour un import réel et robuste, préférer fgets puis strtol avec contrôle de plage et des caractères restants.

Pratiquer avec le TD/TP 1 corrigé · Tous les exercices C.

Repère de lecture : les codes proposés utilisent des constructions disponibles en C11. Les règles du langage et de sa bibliothèque sont consultables dans les projets publics du WG14 (C11) et du WG14 (C23). Les exemples n’utilisent pas les nouveautés propres à C23.

Questions / Réponses

Aucune question. Soyez le premier à poser une question.
★ ★ ★ ★ ★
2 votes. Moyenne 5 sur 5.

Ajouter un commentaire

Anti-spam