Lire et écrire dans un fichier en langage C

30 Aug 2019 30 Aug 2019 51669 vues ESSADDOUKI Mostafa 11 min de lecture

Lecture et écriture dans les fichiers

C fournit trois niveaux de fonctions pour lire et écrire dans les fichiers : caractère par caractère (fgetc/fputc), chaîne par chaîne (fgets/fputs), et données formatées ou binaires (fscanf/fprintf, fread/fwrite).

NiveauÉcritureLectureMode fichierUsage typique
Caractèrefputc()fgetc()TexteCopie octet par octet
Chaînefputs()fgets()TexteLecture/écriture de lignes
Formatéfprintf()fscanf()TexteDonnées structurées lisibles
Binairefwrite()fread()Binaire ("wb"/"rb")Structures, tableaux, performance

1. fputc() et fgetc() — Caractère par caractère


Syntaxe C
int fputc(int ch, FILE *fp);
/* Écrit le caractère ch dans le fichier fp
   Retourne la valeur ASCII de ch, ou EOF en cas d'erreur */

int fgetc(FILE *fp);
/* Lit un caractère du fichier fp et avance le curseur
   Retourne la valeur ASCII du caractère, ou EOF en fin de fichier / erreur */
Rôle du buffer dans fputc / fgetc Bien que ces fonctions semblent travailler caractère par caractère, elles utilisent un buffer interne. Pour fputc, les caractères s'accumulent dans le buffer et sont écrits en bloc sur disque dès que le buffer est plein ou que le fichier est fermé. Pour fgetc, un bloc entier est lu depuis le disque dans le buffer ; les caractères sont ensuite livrés un par un — ce qui rend ces fonctions bien plus efficaces qu'une lecture/écriture disque réelle à chaque appel.

Exemple n°1 — Copier l'entrée standard vers un fichier

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    int   ch;

    f = fopen("test.txt", "w");
    if (f == NULL) {
        perror("Ouverture test.txt");
        exit(1);
    }

    /* Lire depuis stdin, écrire dans le fichier jusqu'à EOF (Ctrl+D / Ctrl+Z) */
    while ((ch = getchar()) != EOF) {
        fputc(ch, f);
    }

    fclose(f);
    printf("Fichier écrit.\n");
    return 0;
}

Exemple n°2 — Lire et afficher un fichier caractère par caractère

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    int   ch;

    f = fopen("test.txt", "r");
    if (f == NULL) {
        perror("Ouverture test.txt");
        exit(1);
    }

    while ((ch = fgetc(f)) != EOF) {
        printf("%c", ch);
    }

    fclose(f);
    return 0;
}

Exemple n°3 — Compter les caractères et les lignes d'un fichier

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    int   ch, nb_chars = 0, nb_lines = 0;

    f = fopen("test.txt", "r");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    while ((ch = fgetc(f)) != EOF) {
        nb_chars++;
        if (ch == '\n') nb_lines++;
    }

    printf("Caractères : %d\n", nb_chars);
    printf("Lignes     : %d\n", nb_lines);

    fclose(f);
    return 0;
}
Sortie (fichier : "Bonjour\nMonde\n")
Caractères : 14
Lignes     : 2

2. fputs() et fgets() — Chaîne par chaîne


Syntaxe C
int   fputs(const char *str, FILE *fp);
/* Écrit la chaîne str dans fp (sans ajouter '\n' automatiquement)
   Retourne une valeur >= 0 en cas de succès, EOF en cas d'erreur */

char *fgets(char *str, int n, FILE *fp);
/* Lit au plus n-1 caractères depuis fp dans str, s'arrête à '\n' ou EOF
   Ajoute '\0' en fin — conserve le '\n' dans str
   Retourne str en cas de succès, NULL en fin de fichier ou erreur */
Critèrefputs()fgets()
DirectionÉcriture (mémoire → fichier)Lecture (fichier → mémoire)
Saut de ligneNon ajouté automatiquementConservé dans la chaîne lue
Limite tailleNon (écrit toute la chaîne)Oui — paramètre n
Fin de fichierRetourne NULL

Exemple n°4 — Écrire des lignes saisies dans un fichier

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    FILE *f;
    char  ligne[100];

    f = fopen("notes.txt", "w");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    printf("Saisir des lignes (ligne vide pour terminer) :\n");

    while (fgets(ligne, sizeof(ligne), stdin) != NULL) {
        if (ligne[0] == '\n') break;   /* ligne vide = fin de saisie */
        fputs(ligne, f);               /* écrit la ligne dans le fichier */
    }

    fclose(f);
    printf("Fichier sauvegardé.\n");
    return 0;
}

Exemple n°5 — Lire et afficher un fichier ligne par ligne

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    char  ligne[100];
    int   num = 1;

    f = fopen("notes.txt", "r");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    while (fgets(ligne, sizeof(ligne), f) != NULL) {
        printf("%3d | %s", num++, ligne);
    }

    fclose(f);
    return 0;
}
Sortie (fichier contenant 3 lignes)
  1 | Algorithmes et structures de données
  2 | Programmation en C
  3 | Bases de données
Danger — Ne jamais utiliser gets() La source utilise gets() dans l'exemple 3. Cette fonction est supprimée de la norme C11 car elle ne limite pas la taille de la lecture — elle provoque des dépassements de buffer exploitables. Utiliser toujours fgets(stdin)à la place :
gets(str);                          /* Dangereux — supprimé C11   */
fgets(str, sizeof(str), stdin);     /* Correct et sécurisé        */

3. fprintf() et fscanf() — Données formatées

fprintf / fscanf fprintf() et fscanf() sont les équivalents fichier de printf() et scanf(). Ils acceptent les mêmes spécificateurs de format (%d, %s, %f…) avec un argument supplémentaire : le pointeur de fichier en première position.

Syntaxe C
int fprintf(FILE *fp, const char *format, ...);
/* Comme printf() mais écrit dans fp au lieu de stdout
   Retourne le nb de caractères écrits, ou EOF en cas d'erreur */

int fscanf(FILE *fp, const char *format, ...);
/* Comme scanf() mais lit depuis fp au lieu de stdin
   Retourne le nb de valeurs lues, ou EOF en fin de fichier / erreur */

Exemple n°6 — Écrire des données formatées

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    char  nom[20];
    int   age;

    f = fopen("etudiants.txt", "w");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    printf("Nom : ");
    scanf("%s", nom);
    printf("Âge : ");
    scanf("%d", &age);

    fprintf(f, "%s %d\n", nom, age);   /* écriture formatée dans le fichier */

    fclose(f);
    printf("Enregistré dans etudiants.txt\n");
    return 0;
}

Exemple n°7 — Lire des données formatées et afficher

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *f;
    char  nom[20];
    int   age;

    f = fopen("etudiants.txt", "r");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    /* Lire jusqu'à la fin du fichier */
    while (fscanf(f, "%s %d", nom, &age) == 2) {
        printf("Nom : %-15s | Âge : %d\n", nom, age);
    }

    fclose(f);
    return 0;
}
Sortie
Nom : Mostafa         | Âge : 23
Nom : Ismail          | Âge : 20
Nom : Dounia          | Âge : 22
Astuce — Vérifier le retour de fscanf() fscanf()retourne le nombre de valeurs correctement lues. Vérifier cette valeur dans la condition de boucle protège contre les données malformées et la fin de fichier :
while (fscanf(f, "%s %d", nom, &age) == 2) { ... }
/* Sortie propre si : fin de fichier, ligne mal formée, ou erreur */

4. fwrite() et fread() — Mode binaire

fwrite / fread — E/S binaires fwrite() et fread() écrivent et lisent des blocs d'octets tels qu'ils sont représentés en mémoire — sans conversion ni formatage. Ils sont plus rapides que les fonctions texte et permettent de persister directement des structures, tableaux ou tout type de données.

Syntaxe C
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
/* Écrit n éléments de taille size depuis l'adresse ptr dans fp
   Retourne le nombre d'éléments effectivement écrits */

size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
/* Lit n éléments de taille size depuis fp vers l'adresse ptr
   Retourne le nombre d'éléments effectivement lus */
ParamètreRôleExemple
ptrAdresse source (écriture) ou destination (lecture)&a, tab, &etd
sizeTaille en octets d'un élémentsizeof(int), sizeof(struct etudiant)
nNombre d'éléments à lire/écrire1, 3, N
fpPointeur de fichier (ouvert en mode binaire)f

Exemples d'écriture avec fwrite()

Exemple n°8 — Écrire une variable, un tableau, une structure

#include <stdio.h>
#include <stdlib.h>

struct etudiant {
    char nom[20];
    int  age;
};

int main(void)
{
    FILE *f = fopen("data.bin", "wb");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    /* Écrire une variable int */
    int a = 5;
    fwrite(&a, sizeof(a), 1, f);

    /* Écrire un tableau */
    int tab[4] = {2, 5, 7, 8};
    fwrite(tab, sizeof(tab), 1, f);         /* tableau entier */

    /* Écrire une structure */
    struct etudiant etd = {"Mostafa", 34};
    fwrite(&etd, sizeof(etd), 1, f);

    /* Écrire un tableau de structures (2 éléments sur 3) */
    struct etudiant etds[3] = {{"Mostafa", 32}, {"Ismail", 27}, {"Dounia", 23}};
    fwrite(etds, sizeof(struct etudiant), 2, f);   /* seulement Mostafa et Ismail */

    fclose(f);
    printf("Données binaires écrites.\n");
    return 0;
}

Exemples de lecture avec fread()

Exemple n°9 — Lire et afficher toutes les structures d'un fichier

#include <stdio.h>
#include <stdlib.h>

struct etudiant {
    char nom[20];
    int  age;
};

int main(void)
{
    FILE           *f;
    struct etudiant etd;
    int             num = 1;

    f = fopen("etudiants.bin", "rb");
    if (f == NULL) { perror("Ouverture"); exit(1); }

    /* Lire une structure à la fois — s'arrête quand fread retourne 0 */
    while (fread(&etd, sizeof(etd), 1, f) == 1) {
        printf("Étudiant N°%d : %-15s %d ans\n", num++, etd.nom, etd.age);
    }

    fclose(f);
    return 0;
}

Exemple n°10 — Écrire puis relire un tableau de structures (programme complet)

#include <stdio.h>
#include <stdlib.h>

struct etudiant {
    char nom[20];
    int  age;
};

int main(void)
{
    const int N = 3;
    struct etudiant liste[3] = {
        {"Mostafa", 23},
        {"Ismail",  20},
        {"Dounia",  22}
    };

    /* --- Écriture --- */
    FILE *f = fopen("etudiants.bin", "wb");
    if (f == NULL) { perror("Écriture"); exit(1); }
    fwrite(liste, sizeof(struct etudiant), N, f);
    fclose(f);

    /* --- Lecture --- */
    struct etudiant lu[3];
    f = fopen("etudiants.bin", "rb");
    if (f == NULL) { perror("Lecture"); exit(1); }

    int nb = fread(lu, sizeof(struct etudiant), N, f);
    fclose(f);

    printf("%d enregistrements lus :\n", nb);
    for (int i = 0 ; i < nb ; i++) {
        printf("  %s — %d ans\n", lu[i].nom, lu[i].age);
    }

    return 0;
}
Sortie
3 enregistrements lus :
  Mostafa — 23 ans
  Ismail  — 20 ans
  Dounia  — 22 ans
Attention — Vérifier le retour de fread() fread() retourne le nombre d'éléments effectivement lus, qui peut être inférieur à nen fin de fichier ou en cas d'erreur. Toujours utiliser cette valeur de retour pour détecter la fin de fichier :
/* Correct — boucle sur le retour de fread */
while (fread(&etd, sizeof(etd), 1, f) == 1) { ... }

/* Vérification après fread multiple */
int nb = fread(buf, sizeof(struct etudiant), N, f);
if (nb < N) {
    if (feof(f))   printf("Fin de fichier atteinte\n");
    if (ferror(f)) perror("Erreur de lecture");
}

Récapitulatif

FonctionDirectionGranularitéModeRetourne
fputc(ch, f)Écriture1 caractèreTexteASCII du char, ou EOF
fgetc(f)Lecture1 caractèreTexteASCII du char, ou EOF
fputs(str, f)ÉcritureChaîne entièreTexte≥ 0, ou EOF
fgets(str, n, f)LectureLigne (max n-1 chars)TextePointeur str, ou NULL
fprintf(f, fmt, ...)ÉcritureDonnées formatéesTexteNb chars écrits, ou EOF
fscanf(f, fmt, ...)LectureDonnées formatéesTexteNb valeurs lues, ou EOF
fwrite(ptr, size, n, f)ÉcritureBloc d'octetsBinaireNb éléments écrits
fread(ptr, size, n, f)LectureBloc d'octetsBinaireNb éléments lus

Discussion (0)

Soyez le premier à laisser un commentaire !

Laisser un commentaire

Votre commentaire sera visible après modération.