Les Fichiers Binaires en C

Ce cours détaille la manipulation des fichiers binaires en C. Apprenez à utiliser les fonctions de lecture et d'écriture, à gérer l'accès direct avec fseek et ftell, et à enregistrer des structures de données complexes en mémoire.

D'après le document Les Fichiers Binaires en C

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Les Fichiers Binaires en C

Document source

Les Fichiers Binaires en C

Computer Science, Programming in C · PDF · 10 pages · 2011

Afficher l'aperçu du document

Consulter le document original →

Ce cours pratique porte sur la manipulation des fichiers binaires en langage C. Il permet d’apprendre à créer, lire, écrire et modifier des fichiers binaires, ainsi qu’à gérer les structures de données complexes dans ces fichiers. Pour réaliser ce travail pratique, il est nécessaire d’avoir un environnement de développement C avec un compilateur compatible et une connaissance de base des fichiers et des structures en C.

Objectifs pédagogiques

  • Comprendre la différence entre fichiers binaires et fichiers texte en C.
  • Utiliser les fonctions fread, fwrite, fopen, fclose, feof, fseek et ftell.
  • Créer, remplir, lire et modifier des fichiers binaires contenant des données simples (entiers) et complexes (structures).
  • Gérer le pointeur de fichier pour un accès direct aux données dans un fichier binaire.
  • Appliquer la détection de fin de fichier avec feof.

Prérequis et préparation

  • Connaissance des bases du langage C, notamment les pointeurs, les structures et la gestion des fichiers.
  • Un compilateur C (gcc, clang ou autre) et un éditeur de texte.
  • Compréhension des notions d’octets, de blocs mémoire et de flux de fichiers.
  • Accès à la bibliothèque standard C (stdio.h, stdlib.h).

Manipulation des fichiers binaires : lecture et écriture

En C, un fichier est vu comme une suite ordonnée d’octets. La notion d’enregistrement n’existe pas intrinsèquement. On peut choisir d’écrire ou lire les données sous forme binaire (copie brute de la mémoire) ou sous forme formatée (texte). Ce cours se concentre sur la forme binaire, avec les fonctions fread et fwrite.

Pour écrire dans un fichier binaire, on utilise :

fwrite(&bloc, sizeof(bloc), n, fp);

où :

  • &bloc est l’adresse mémoire du bloc à écrire.
  • sizeof(bloc) est la taille en octets d’un bloc.
  • n est le nombre de blocs à écrire.
  • fp est le pointeur vers le fichier ouvert.

La fonction retourne le nombre de blocs effectivement écrits.

Pour lire un fichier binaire :

fread(&bloc, sizeof(bloc), n, fp);

Les arguments sont similaires à fwrite, et la fonction retourne le nombre de blocs lus.

Il est important de noter que :

  • fwrite(&bloc, sizeof(bloc), n, fp); peut écrire partiellement en cas d’erreur.
  • fwrite(&bloc, n * sizeof(bloc), 1, fp); écrit tout ou rien.
  • De même pour fread concernant la lecture.

Ouverture et fermeture des fichiers

La fonction fopen ouvre un fichier et retourne un pointeur sur une structure FILE associée au fichier :

FILE *fp;
fp = fopen("nom_fichier", "wb+");

Les modes d’ouverture sont :

  • r : lecture seule, le fichier doit exister.
  • w : écriture seule, crée ou écrase le fichier.
  • a : écriture en fin de fichier, crée si absent.
  • r+ : lecture et écriture, fichier existant.
  • w+ : lecture et écriture, crée ou écrase.
  • a+ : lecture et écriture en fin, crée si absent.
  • On peut ajouter b pour binaire (ex. wb+).

La fermeture du fichier se fait avec :

fclose(fp);

Exemple pratique 1 : fichier binaire d’entiers

Ce programme permet de saisir des entiers, de les écrire dans un fichier binaire, puis de les relire et afficher.

#include <stdio.h>

void main() {
    char nomfich[21];
    int n;
    FILE *fp;

    printf("saisir nom fichier ");
    scanf("%s", nomfich);
    fp = fopen(nomfich, "wb+");

    do {
        printf("donner un entier; 0 pour s'arreter  ");
        scanf("%d", &n);
        if (n != 0) fwrite(&n, sizeof(int), 1, fp);
    } while (n != 0);

    rewind(fp);

    while (!feof(fp)) {
        fread(&n, sizeof(int), 1, fp);
        if (!feof(fp)) printf("\n  %d\n", n);
    }

    fclose(fp);
}

La fonction rewind(fp) replace le pointeur au début du fichier pour la lecture. La boucle lit jusqu’à la fin du fichier détectée par feof(fp).

Exemple pratique 2 : fichier binaire d’étudiants

On manipule ici une structure complexe ETUDIANT contenant un numéro, un nom, un tableau de notes et une date de naissance.

struct date {
    int jour;
    int mois;
    int annee;
};
typedef struct date DATE;

struct etudiant {
    int ce;           // numéro carte d’étudiant
    char nom[30];
    float notes[5];
    DATE date_naiss;
};
typedef struct etudiant ETUDIANT;

Le programme propose les fonctions suivantes :

  • ouverture : ouvrir un fichier binaire en mode wb+.
  • remplir_fichier : saisir des étudiants jusqu’à ce que ce == -1, et écrire dans le fichier.
  • affichage_fichier : lire et afficher tous les étudiants du fichier.

Extrait de la saisie d’un étudiant :

int saisir_etudiant(ETUDIANT *e) {
    printf("\n saisir ce \n");
    scanf("%d", &e->ce);
    if (e->ce == -1) return 0;
    printf("\n saisir nom    ");
    scanf("%s", e->nom);
    printf("\n saisir les notes ");
    for (int i = 0; i < 5; i++)
        scanf("%f", &e->notes[i]);
    printf("\n saisir la date de naissance \n");
    scanf("%d%d%d", &e->date_naiss.jour, &e->date_naiss.mois, &e->date_naiss.annee);
    return 1;
}

Pour afficher les notes :

void afficher_notes(float *t) {
    for (int i = 0; i < 5; i++)
        printf("%f ", t[i]);
}

Pour afficher un étudiant :

void afficher_etudiant(ETUDIANT etd) {
    printf("\n  %4d %20s \n", etd.ce, etd.nom);
    afficher_notes(etd.notes);
    printf("\n  %2d %2d %4d \n", etd.date_naiss.jour, etd.date_naiss.mois, etd.date_naiss.annee);
}

Accès direct et modification dans un fichier binaire

On peut modifier un enregistrement à une position donnée dans un fichier binaire grâce à fseek et ftell.

Exemple pour modifier l’étudiant en position pos :

printf("saisir la position de l'etudiant à modifier ");
scanf("%d", &pos);

fseek(fp, (pos-1) * sizeof(ETUDIANT), SEEK_SET);

long p = ftell(fp);
fread(&etd, sizeof(ETUDIANT), 1, fp);
afficher_etudiant(etd);

modifier_etudiant(&etd);

fseek(fp, p, SEEK_SET);
fwrite(&etd, sizeof(ETUDIANT), 1, fp);

La fonction modifier_etudiant permet de saisir de nouvelles données pour l’étudiant.

On peut aussi utiliser un déplacement relatif :

fseek(fp, -(long)sizeof(ETUDIANT), SEEK_CUR);
fwrite(&etd, sizeof(ETUDIANT), 1, fp);

Gestion du pointeur de fichier

Le pointeur de fichier indique la position du prochain octet à lire ou écrire. Il est possible de le manipuler avec :

  • rewind(fp) : revient au début du fichier.
  • fseek(fp, offset, origin) : déplace le pointeur.
  • ftell(fp) : retourne la position actuelle du pointeur.

Les valeurs possibles pour origin sont :

  • SEEK_SET (0) : début du fichier.
  • SEEK_CUR (1) : position courante.
  • SEEK_END (2) : fin du fichier.

Exemple pour obtenir la taille d’un fichier :

fseek(fp, 0, SEEK_END);
long taille = ftell(fp);
printf("la taille du fichier est %ld\n", taille);
printf("le nombre d'employés est %ld\n", taille / sizeof(EMPLOYE));

Résultats attendus

  • Un fichier binaire contenant les données saisies (entiers ou structures).
  • Affichage correct des valeurs lues, identique à celles saisies.
  • Modification effective d’un enregistrement à la position demandée.
  • Gestion correcte de la fin de fichier avec feof, sans lecture erronée.
  • Utilisation fonctionnelle des fonctions fseek et ftell pour accès direct.

Pièges courants

  • Ne pas vérifier si fopen retourne NULL, ce qui indique un échec d’ouverture.
  • Confondre les modes d’ouverture, par exemple ouvrir un fichier en mode lecture alors qu’il n’existe pas.
  • Ne pas utiliser rewind avant de relire un fichier déjà écrit.
  • Utiliser feof avant la lecture : feof ne devient vrai qu’après une tentative de lecture au-delà de la fin.
  • Ne pas gérer correctement la taille des blocs dans fread/fwrite, ce qui peut provoquer des erreurs de lecture ou écriture.
  • Oublier que fwrite avec un seul bloc de taille n*sizeof(bloc) est atomique, alors que plusieurs blocs peuvent être partiellement écrits.
  • Ne pas gérer les retours de fread/fwrite pour détecter les erreurs.
  • Calcul incorrect de la position dans fseek, notamment en oubliant de multiplier par sizeof(type).
  • Ne pas fermer le fichier avec fclose, ce qui peut entraîner une perte de données.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions