Cours Atelier de Programmation Avancée - Fichiers Binaires

Page 1 sur 10Lecteur de document UniversityLib

Cours Atelier de Programmation Avancée - Fichiers Binaires

Computer Science · lab

Voir tous les documents en programmation

École Supérieure de Technologie

et d’Informatique

A.U. 2011/2012

Cours atelier de programmation avancée

Chapitre: Les fichiers binaires (Partie I : 10 pages)

1ère année LA ARS

Les fonctions d’écriture et de lecture binaire : fread et fwrite

Les fonctions d’écriture et de lecture formatée : fprintf, fscanf, fputs, fgets

Les fonctions d’écriture et de lecture mixtes : fputc, fgetc.

En C, un fichier est considéré comme une collection ordonnée d’octets. La notion

d’enregistrement n’existe plus.

On peut choisir entre deux manières de représenter (archiver) l’information dans un fichier :

(cid:1) Sous forme binaire : copier l’information dans le fichier telle qu’elle figure en

mémoire (fonction d’écriture dans le fichier: fwrite ; fonction de lecture à partir du

fichier : fread)

(cid:1) Sous forme formatée : exprimer l’information sous la forme d’une suite de caractères

(càd d’octets contenant des codes de caractères) (fonctions de lecture à partir d’un

fichier: fscanf, fgets ; fonctions d’écriture dans un fichier: fprintf, fputs).

Les fichiers créés en binaire ne peuvent être exploités que dans l’environnement dans lequel

ils ont été créés, ou pour le moins, dans un environnement utilisant le même codage.

La forme formatée est souvent utilisée pour « porter » des données d’un environnement à un

autre, et ce malgré le coût supplémentaire en temps induit par les conversions nécessaires

aussi bien lors de la lecture que lors de l’écriture.

D’une manière générale :

(cid:1) Si on souhaite dans une implémentation donnée, écrire des fichiers susceptibles d’être

lus par des logiciels manipulant des textes, ou encore lire des fichiers créés par de tels

logiciels. Dans ce cas, il est nécessaire d’utiliser des fichiers textes, afin d’assurer le

transcodage nécessaire entre code interne et code externe.

(cid:1) Si on est certain que les fichiers seront toujours manipulés par des programmes C

dans la même implémentation, dans ce cas, on peut se permettre d’utiliser des fichiers

binaires.

Il existe deux techniques d’accès aux fichiers:

(cid:1) Accès séquentiel: consiste à traiter les informations séquentiellement, càd dans l’ordre

où elles apparaissent dans le fichier, aussi bien en lecture qu’en écriture.

(cid:1) Accès direct: consiste à se placer immédiatement sur l’information souhaitée, sans

avoir à parcourir celles qui la précèdent.

Notion de flux

Dans bon nombre de langages, les fichiers ne se manipulent pas directement par leur « nom

externe », mais par un « nom interne » choisi librement par le programme. L’association du

nom externe au nom interne de fichier se fait au moment de l’ouverture par fopen.

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 1

Le nom interne est un pointeur sur une structure de type FILE (synonyme prédéfini par

typedef dans stdio.h).

Exemple :

FILE *fp ; // fp représente un flux

L’identificateur fp est un nom interne de fichier.

fp= fopen (« c:\\info.txt », « wb+ ») ; // fp est le nom interne du fichier info.txt

Cette instruction crée la correspondance entre nom externe et nom interne.

On parle de flux binaire ou de flux texte pour désigner un flux associé à un fichier ouvert en

mode binaire ou en mode texte.

La structure de type FILE ainsi associée au fichier comporte un certain nombre

d’informations, permettant d’assurer la bonne gestion du fichier tels que :

(cid:1) Un pointeur à l’intérieur du fichier

(cid:1) Un indicateur d’erreur

(cid:1) Un indicateur de fin de fichier

(cid:1) etc

En matière de traitement de fichiers en C, on distingue :

(cid:1) Le mode d’ouverture du fichier (binaire ou texte), ce qui amène à parler de flux

binaire ou de flux texte. Certaines implémentations ne font pas cette distinction.

(cid:1) Le type des opérations que l’on y effectue : binaires ou formatées, et ce

indépendamment du mode d’ouverture

(cid:1) Le type d’accès au fichier : séquentiel ou direct.

Les opérations relatives aux fichiers binaires

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

Permet de transférer « n » blocs consécutifs de même taille « sizeof(bloc) » vers le

fichier « fp », à partir d’une adresse donnée de la mémoire «&bloc». (càd écrire sous forme

binaire des informations dans le fichier).

fwrite possède 4 arguments:

(cid:1) &bloc : Adresse en mémoire d’un bloc d’informations à partir de la quelle seront

copiées les informations à écrire dans le fichier.

(cid:1) sizeof(bloc) : La taille en octets d’un bloc

(cid:1) n : Le nombre de blocs de cette taille à transférer (à écrire) dans le fichier

(cid:1)

fp : Descripteur du fichier (nom du flux concerné): l’adresse de la structure de type

FILE décrivant le fichier.

La valeur de retour de fwrite correspond au nombre de blocs effectivement écrits dans le

fichier.

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

Permet d’écrire n blocs, chacun de taille

sizeof (bloc).

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

Permet d’écrire 1 bloc de taille

n*sizeof(bloc).

Ces deux instructions sont équivalentes. La différence apparaît en cas d’erreur d’écriture:

(cid:1) La première peut écrire dans le fichier les premiers blocs.

(cid:1) La deuxième : le bloc est écrit en totalité, ou bien n’est pas écrit.

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 2

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

Permet de lire sous forme binaire (brute) à partir du fichier « fp », au maximum « n » blocs de

Publicité

taille « sizeof(bloc) » octets, et les range à partir de l’adresse « &bloc » dans la mémoire.

La fonction fread possède 4 arguments:

(cid:1) Adresse en mémoire à partir de la quelle seront rangées les informations lues à partir

du fichier.

(cid:1) La taille en octet de chaque bloc

(cid:1) Le nombre de blocs à lire

(cid:1) Descripteur du fichier

La valeur de retour de fread correspond au nombre de blocs effectivement lus à partir du

fichier.

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

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

Permet de lire n blocs, chacun de taille sizeof

(bloc).

Ces deux instructions sont équivalentes. La différence apparaît en cas d’erreur de lecture:

Permet de lire 1 bloc de taille n*sizeof(bloc).

(cid:1) La première peut lire les premiers blocs à partir du fichier.

(cid:1) La deuxième : le bloc est lu en totalité, ou bien n’est pas lu.

La fonction fclose

Réalise la fermeture du fichier.

Le « pointeur de fichier » indique l’emplacement auquel commencera la prochaine

opération de lecture ou d’écriture.

Un « pointeur de fichier » = « emplacement dans un fichier » : est un nombre qui précise le

rang du prochain octet à lire ou à écrire dans le fichier, il agit au niveau de l’octet.

En C, la notion d’enregistrement est quasi absente et l’accès direct peut se faire à un octet

quelconque de rang donné (voir plus loin la fonction fseek). Donc, il faut être en mesure de

calculer correctement le numéro de l’octet voulu.

Détection de la fin de fichier avec feof

La structure de type FILE associée à un fichier comporte un indicateur de fin de fichier qui

peut être examiné à l’aide de la fonction feof. La lecture des derniers octets d’un fichier ne

permettra pas d’en détecter la fin, il faudra tenter de lire au-delà, càd au moins un octet

inexistant.

feof prend la valeur vrai (non nul) lorsque la fin de fichier a été rencontrée. feof ne travaille

pas par anticipation, càd il n’est pas suffisant d’avoir lu le dernier octet du fichier pour que

cette condition prenne la valeur vrai. Il est nécessaire d’avoir tenté de lire au-delà. C’est

pourquoi il faut examiner cette condition après l’appel de fread et non avant.

La fonction fopen

fopen possède deux arguments :

(cid:1) Le nom du fichier concerné, fournit sous forme d’une chaîne de caractère. Il peut

également comporter une information (chemin, répertoire,..) permettant de préciser

l’endroit où se trouve le fichier.

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 3

char nom[30] ;

gets(nom) ;

fp= fopen (nom, « wb+ ») ;

ou bien

fp=fopen (« c:\\données\\essai.txt », « wb+ ») ;

(cid:1) Une indication fournie sous forme d’une chaîne de caractères, précisant ce que l’on

souhaite faire avec le fichier (r, w, rb, rw, etc).

La fonction fopen fournit en résultat un pointeur sur une structure FILE qu’elle a alloué

dynamiquement, lorsque l’opération d’ouverture a réussi. Dans le cas contraire, elle fournirait

un pointeur nul.

Les différentes possibilités d’ouverture d’un fichier

(cid:2) r: (read) lecture seulement. le fichier doit exister

(cid:2) w: (write) écriture seulement. si le fichier n’existe pas, il est créé. s’il existe, son

(ancien) contenu est perdu.

(cid:2) a: (append) écriture en fin de fichier. si le fichier existe déjà, il sera étendu. s’il

n’existe pas, il sera créé. on se ramène alors au mode w.

(cid:2) r+: mise à jour, (lecture et écriture). le fichier doit exister.

(cid:2) w+: création pour mise à jour. si le fichier existe, son ancien contenu sera détruit. s’il

n’existe pas, il sera créé.

(cid:2) a+: extension et mise à jour. si le fichier n’existe pas, il sera créé. s’il existe, le

pointeur sera positionné en fin de fichier.

(cid:2) t ou b, lorsque l’implémentation distingue les fichiers de texte des autres, il est

possible d’ajouter l’une de ces deux lettres à chacun des 6 modes précédents.

(cid:1)

t: fichier texte

(cid:1) b: fichier binaire

Exemple1 : remplir et afficher un fichier binaire d’entiers

#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);

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 4

rewind (fp);

while ( !feof(fp))

{

fread(&n,sizeof(int),1,fp);

Publicité

if(!feof(fp)) printf("\n %d\n",n);

}

fclose (fp);

}

Ou bien

do

{

fread(&n,sizeof(int),1,fp);

if(!feof(fp)) printf("\n %d\n",n);

}

while (!feof(fp));

Même programme en utilisant les fonctions

#include<stdio.h>

#include<stdlib.h>

void ouverture (FILE **fp)

{

char nomfich[21];

printf("saisir nom fichier ");

scanf("%s",nomfich);

*fp=fopen(nomfich, "wb+");

if (!*fp) exit(-1);

}

void remplir_fichier (FILE *fp)

{

int n;

do

{

printf("donner un entier; 0 pour s'arreter ");

scanf("%d",&n);

if (n!=0) fwrite (&n, sizeof(int),1,fp);

}

while(n!=0);

}

void afficher_fichier (FILE *fp)

{

int n;

while ( !feof(fp))

{

fread(&n,sizeof(int),1,fp);

if(!feof(fp)) printf("\n %d\n",n);

}

}

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 5

void main()

{

FILE *fp;

ouverture (&fp);

remplir_fichier(fp);

rewind (fp);

afficher_fichier(fp);

fclose (fp);

}

Exemple 2 : remplir et afficher un fichier binaire d’etudiants : le nombre d’étudiants n’est pas

connu à l’avance. La condition d’arrêt est lorsque ce=-1.

#include<stdio.h>

#include<stdlib.h>

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;

/*/

void ouverture (FILE **fp)

{

char nf[20];

printf("saisir nom fichier");

gets(nf);

*fp=fopen(nf,"wb+");

}

/**/

void remplir_notes (float *t)

{

int i;

for (i=0; i<5; i++)

scanf("%f", t+i);

}

/**/

void afficher_notes (float *t)

{

int i;

for (i=0; i<5; i++)

Publicité

printf("%f", *(t+i));

}

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 6

/**/

int saisir_etudiant (ETUDIANT *e)

{

// condition d'arrêt: cin=-1

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 ");

remplir_notes(e->notes);

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;

}

/**/

void remplir_fichier(FILE *fp)

{

ETUDIANT etd;

while ( saisir_etudiant (&etd)) // ou bien while (saisir_employe(&emp) ==1)

fwrite(&etd, sizeof(ETUDIANT), 1,fp);

}

//

void remplir_fichier2 (FILE *fp)

ETUDIANT e;

{

while(1)

{

printf("\n saisir ce \n");

scanf("%d", &e.ce);

if(e.ce==-1) break;

printf("\n saisir nom ");

scanf("%s", e.nom);

printf("\n saisir les notes ");

remplir_notes(e.notes);

printf("\n saisir la date de naissance \n");

scanf("%d%d%d",&e.date_naiss.jour, &e.date_naiss.mois, &e.date_naiss.annee);

fwrite(&e, sizeof(ETUDIANT), 1,fp);

}

}

//

void affichage_fichier(FILE *fp)

{

ETUDIANT etd;

while(1)

{

fread(&etd,sizeof(ETUDIANT),1,fp);

if(feof(fp)) break;

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);

}

}

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 7

/*/

void affichage_fichier2(FILE *fp)

{

ETUDIANT etd;

fread(&etd,sizeof(ETUDIANT),1,fp);

while(!feof(fp))

{

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);

fread(&etd,sizeof(ETUDIANT),1,fp);

}

}

/*/

void main()

{

FILE *fp;

ouverture (&fp);

remplir_fichier(fp); //ou bien remplir_fichier2(fp);

rewind(fp);

affichage_fichier(fp); // ou bien affichage_fichier2(fp) ;

fclose(fp);

}

/*/

La structure de type FILE associée à un fichier comporte un indicateur de fin de fichier qui

peut être examiné à l’aide de la fonction feof. Cet indicateur est extrêmement pratique pour

lire séquentiellement un fichier dont on ne connaît pas la taille.

feof(fp) : prend la valeur vrai (non nul) lorsque la fin du fichier a été rencontrée.

//

Après chaque opération de lecture ou d’écriture, le pointeur de fichier est incrémenté du

nombre d’octets transférés.

Publicité

Il est possible d’agir directement sur ce pointeur à l’aide de la fonction fseek. Ceci permet de

réaliser des lectures ou des écritures en n’importe quel point du fichier sans avoir besoin de

parcourir toutes les informations qui précèdent (accès direct).

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

OU BIEN

fseek(fp,sizeof(int) * (pos-1), 0);

=> Déplacement du pointeur de fichier de « sizeof(int) * (pos-1) » octets par rapport au

début du fichier (accès direct).

Cette fonction a trois arguments :

(cid:1) Le fichier concerné.

(cid:1) Un entier de type long spécifiant la valeur que l’on souhaite donner au pointeur de

fichier (déplacement).

(cid:1) Déplacement du pointeur de fichier à partir :

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 8

o Du début du fichier : SEEK_SET ou bien 0.

o De la position courante : SEEK_CUR ou bien 1 (le déplacement peut être

négatif).

o De la fin du fichier : SEEK_END ou bien 2.

Exemple :

…..

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);

}

/*/

void modifier_etudiant (ETUDIANT *e)

{

printf("\n saisir les nouvelles infos de l'etudiant \n");

printf("\n saisir ce \n");

scanf("%d", &e->ce);

printf("\n saisir nom ");

scanf("%s", e->nom);

printf("\n saisir les notes ");

remplir_notes(e->notes);

printf("\n saisir la date de naissance \n");

scanf("%d%d%d",&e->date_naiss.jour, &e->date_naiss.mois, &e->date_naiss.annee);

}

/*/

void main()

{

FILE *fp;

int pos;

long p;

ETUDIANT etd;

ouverture (&fp);

remplir_fichier(fp); //ou bien remplir_fichier2(fp);

rewind(fp);

printf("saisir la position de l'etudiant à modifier ");

scanf("%d",&pos);

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

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);

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 9

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

fread(&etd,sizeof(ETUDIANT),1,fp);

afficher_etudiant(etd);

modifier_etudiant(&etd);

fseek(fp, -(long)sizeof(ETUDIANT), SEEK_CUR);

fwrite(&etd, sizeof(ETUDIANT), 1,fp);

rewind(fp);

affichage_fichier(fp); // ou bien affichage_fichier2(fp) ;

fclose(fp);

}

D’une manière générale :

long p ;

FILE *fp ;

p=ftell(fp) ; / pour mémoriser une position /

fseek(fp, p, SEEK_SET); / revenir à cette position plus tard /

ftell fournit la position courante du pointeur de fichier. On peut l’utiliser pour mémoriser une

position à la quelle on souhaite revenir ultérieurement.

Cette fonction peut donner la taille d’un fichier, et le nombre d’employés :

long taille ;

fseek(fp,0,SEEK_END) ;

taille = ftell(fp);

printf("la taille du fichier est %ld", taille);

printf("\n le nombre d'employés est %d", taille/sizeof(EMPLOYE));

rewind(fp) (cid:3)(cid:3)(cid:3)(cid:3) fseek(fp,0,0) ;

Mme Wiem Yaiche Elleuch

les fichiers binaires

Page 10