Introduction aux fichiers
Fichiers (type FILE*)
Voici quelques questions pour vous aider à synthétiser et retenir des contenus qui nous paraissent essentiels dans cette section :
Quel type permet d’ouvrir ou de créer un fichier ? Avec quelle fonction ?
Lors de l’ouverture d’un fichier à quoi correspondent les modes a, r et w ?
Comment obtenir un fichier binaire ?
Comment spécifier un chemin d’accès ?
Quelle fonction permet d’écrire dans un fichier binaire ?
Quelle fonction permet de lire dans un fichier binaire ?
Comment détecter la fin d’un fichier binaire ?
Comment se déplacer dans un fichier ?
Comment détecter la fin d’un fichier texte ?
Quelles sont les principales fonctions de lecture et d’écriture dans un fichier texte ?
Quelles sont les fonctions de lecture et d’écriture de texte formaté ?
Quels problèmes posent la sauvegarde sur fichier d’éléments dynamiques ?
Notions de base
1. Le type FILE*
Dans un programme C, un fichier est toujours une structure de type FILE définie dans la bibliothèque stdio.h et manipulée via son adresse par un pointeur FILE*. Pour utiliser un fichier dans un programme, ou une fonction du programme, la première chose à faire est de déclarer un FILE* :
#include <stdio.h>
int main()
{
FILE*f;
(...)
return 0;
}
2. Ouverture et fermeture d’un fichier
Dans la librairie standard stdio.h, la fonction :
FILE* fopen( const char* name ,const char* mode);
permet d’ouvrir un fichier existant ou de créer un fichier. Cette fonction ouvre le fichier dont le nom comprenant le chemin d’accès est spécifié au premier paramètre et selon le mode donné par le second paramètre. Les deux sont des chaînes de caractères. Il y a six modes possibles : r, w, a, r+, w+, a+ et le caractère "b" ajouté ensuite permet de sélectionner une entrée/sortie en mode binaire.
Voici un tableau récapitulatif des différents modes possibles :
Mode |
Accès |
Positionnement en écriture |
Si le fichier existe |
Si le fichier n’existe pas |
r |
Lecture |
au début |
ouverture |
erreur |
w a |
Écriture Écriture |
au début à la fin |
initialisation ouverture |
création création |
r+ w+ a+ |
Lecture et écriture |
au début au début à la fin |
ouverture initialisation ouverture |
erreur création création |
Suffixe b : à ajouter pour les entrées/sorties binaires. |
Attention, l’initialisation d’un fichier existant signifie qu’il est ramené à une taille nulle, c’est-à-dire que toutes les données qu’il contient sont perdues.
Pour refermer un fichier précédemment ouvert, la librairie stdio.h propose la fonction :
int fclose(FILE*);
Cette fonction referme le fichier indiqué via le pointeur au paramètre p. Elle retourne EOF sur erreur et zéro sinon. EOF est une valeur sentinelle qui indique la fin du fichier.
Exemple d’ouverture/fermeture de fichier en mode binaire :
#define _CRT_SECURE_NO_WARNINGS // sous Visual Studio uniquement
#include <stdio.h>
int main() ...
Fichiers binaires
1. Écriture et lecture en mode binaire
L’utilisation des fichiers binaires repose sur deux fonctions uniquement : une pour l’écriture et une pour la lecture. Ces deux fonctions sont dans la librairie standard stdio.h.
Pour écrire (save) des données :
size_t fwrite ( const void*, size_t, size_t, FILE* );
Cette fonction écrit sur le fichier spécifié en p4, p3 objets de taille p2 en octet, rangés à partir de l’adresse p1. Elle retourne le nombre d’objets effectivement écrits.
Pour lire (load) les données d’un fichier :
size_t fread ( void*, size_t, size_t, FILE*);
Soit p1, p2, p3, p4, les paramètres spécifiés dans la fonction.
Cette fonction lit au plus p3 objets de taille p2 en octet sur le fichier spécifié en p4 et les copie à l’adresse p1. Elle retourne le nombre d’objets effectivement lus.
Exemple d’utilisation :
#include <stdio.h>
#include <stdlib.h>
#define NB_POINT 10
typedef struct point {
int x, y;
}t_point;
void init(t_point t[]);
void affiche(t_point t[]);
int main()
{
FILE* f;
t_point...
Écriture et lecture en mode texte
Certaines des fonctions présentées dans ce module sont également présentées dans le module sur les chaînes de caractères. Elles y sont utilisées avec les fichiers d’entrée-sortie standard stdin et stdout. Il s’agit maintenant de les employer plus largement avec toutes sortes de fichiers créés dans un programme. Il y a dans ce module d’autres exemples d’utilisation.
1. Détecter la fin d’un fichier : EOF et feof()
En mode texte surtout, détecter la fin d’un fichier est souvent nécessaire. Il y a deux méthodes. La première du fait de la valeur EOF et la seconde avec la fonction feof().
Le caractère de fin de fichier EOF ------- <stdio.h>
La fin des fichiers texte et binaire est marquée par une valeur définie par une macro constante EOF déclarée dans stdio.h. Cette valeur vaut en général -1 mais elle peut varier d’un environnement à l’autre. Dans les tests qui l’utilisent, il est plus sûr de toujours utiliser EOF plutôt que -1.
La plupart des fonctions du mode texte utilisent la valeur EOF pour signifier la fin du fichier. Cette valeur est aussi utilisée comme retour d’erreur, par exemple pour la fonction fclose().
int feof ( FILE*) ------- <stdio.h>
Cette fonction retourne vrai si la position courante dans le fichier passé en paramètre est à la fin et faux sinon. Cette fonction peut être utilisée pour les deux modes, texte et binaire.
2. Lecture/écriture de caractères
int fgetc ( FILE*) ------- <stdio.h>
Cette fonction retourne un caractère lu sur le fichier spécifié en paramètre et EOF en cas d’erreur ou de détection de la fin du fichier. La macro int getc(FILE*) en est une autre forme équivalente.
int fputc (int, FILE*) ------- <stdio.h>
Cette fonction écrit sur le fichier spécifié en p2 le caractère spécifié en p1. Elle retourne le caractère p1, sinon en cas d’erreur elle retourne EOF.
Exemple d’utilisation
Le programme ci-dessous ouvre en lecture seule le fichier entree.txt....
Sauvegarde d’éléments dynamiques
1. Sauvegarder et récupérer un tableau dynamique
Lors d’une sauvegarde de données obtenues dynamiquement, la taille peut être sauvegardée au début ou à la fin du fichier mais ce n’est pas obligatoire. En revanche, lors du chargement des données, il est nécessaire d’allouer la mémoire nécessaire des variables auxquelles sont affectées les données du fichier. Par exemple :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct point{
int x,y;
}t_point;
void init (t_point**t,int nb);
void affiche (t_point t[],int nb);
int main()
{
FILE*f;
t_point*data;
t_point*recup=NULL;
int nb;
srand(time(NULL));
if (fopen_s(&f,"test.bin", "wb+")==0){
// allocation et initialisation d'un tableau dynamique
// de taille aléatoire
nb=1+rand()%20;
init(&data,nb); ...
Expérimentation : récapitulation sauvegardes binaires
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
// macro-constante pour la taille des tableaux statiques
#define NBMAX 5
// le type de data à sauvegarder et récupérer
typedef struct
{
int x, y;
}t_acteur;
// pour tableau d'acteurs statique ou dynamique
void Init(t_acteur t[], int nb);
void Affiche(t_acteur t[], int nb);
void SaveTabStatic(char* nameFile, t_acteur t[]);
void LoadTabStatic(char* nameFile, t_acteur t[]);
void SaveTabDyn(char* nameFile, t_acteur t[], int nb);
int LoadTabDyn(char* nameFile, t_acteur** t);
// tableau statique de pointeurs
void InitActeur(t_acteur* a);
void InitTabPtr(t_acteur* t[]);
void AfficheTabPtr(t_acteur* t[]);
void SaveTabPtr(char* nameFile, t_acteur* t[]);
void LoadTabPtr(char* nameFile, t_acteur* t[]);
/************************************************************
*************************************************************/
int main()
{
t_acteur tabStat[NBMAX];
t_acteur *tabDyn;
t_acteur* tabPtr[NBMAX];
int nbmax;
srand((unsigned)time(NULL));
// TABLEAU STATIQUE
printf("SEQUENCE TAB STATIQUE :\n");
Init(tabStat, NBMAX);
Affiche(tabStat, NBMAX);
//Sauvegarde du tableau initialisé
SaveTabStatic("tabStatic.bin", tabStat);
// effacement du tableau : mise à 0 de tous les octets
memset(tabStat, 0, sizeof(t_acteur)*NBMAX);
Affiche(tabStat...
Mise en pratique : fichiers
Exercice 1
Dans un programme, ouvrir en lecture un fichier dont le nom est donné par l’utilisateur. Indiquer si l’opération a réussi. Si l’opération échoue, le fichier n’existe pas, le créer et indiquer le résultat. Faire tourner le programme une première fois, le fermer et le lancer une deuxième fois pour vérifier que le fichier a bien été créé et s’ouvre correctement. Aller sur le disque voir où le fichier se trouve. Ne pas oublier dans le programme de fermer le fichier quand il n’a plus besoin d’être ouvert.
Exercice 2
Écrire un programme qui ouvre ou crée un fichier dont le nom, l’emplacement et le mode sont entrés par l’utilisateur. Ne pas oublier de fermer le fichier lorsque cela a réussi et qu’un message a été transmis à l’utilisateur.
Exercice 3
Un programme crée un fichier qui se trouve dans un dossier nommé test dans le répertoire du programme. Vérifier que le fichier est bien sur le disque dur. Modifier le programme pour ouvrir le fichier en lecture uniquement et relancer le programme. Ne pas oublier de fermer le fichier.
Exercice 4
Avec le Bloc-notes créer un fichier qui est sauvé dans un répertoire distant du programme.
Par rapport au programme il faut remonter de trois niveaux et redescendre de quatre niveaux pour trouver le fichier. Écrire le programme qui ouvre le fichier et le referme.
Exercice 5
Écrire un programme qui demande à l’usager d’entrer des mots un à un, qui stocke ces mots à la fin d’un fichier texte, puis qui affiche le contenu du fichier complet. Initialement, le programme doit créer le fichier s’il n’existe pas, mais ne doit pas perdre son contenu s’il existe...