Cours de C - Les fichiers

 


Sur tous les ordinateurs, quel que soit le système d'exploitation, on a besoin de traiter des fichiers, c'est à dire des données enregistrées non pas en mémoire vive (RAM), mais en mémoire dite de masse (disquettes ou disques durs). La gestion de ces fichiers (découpage et formatage du support, allocation, etc...) est confiée au système d'exploitation, c'est même son rôle premier.


Principes

En C, les fichiers sont considérés comme des flux de données, par lesquelles peuvent transiter tous types (caractères, chaînes, entiers, tableaux). La première chose à faire, c'est de demander au système l'ouverture du flux (représentez vous un flux comme un mouvement d'eau par exemple : l'ouverture correspont à l'ouverture du robinet) , puis de lire et/ou d'écrire dans ce flux, puis de le refermer (comme le robinet, bien sûr).

En C, il y a deux méthodes (principalement). On traite le flux avec un pointeur (de type FILE) ou avec un entier qui l'identifie. Les deux méthodes sont relativement similaires. Je vais personnelement traiter la première, mais l'autre est aussi bien.

Lors de l'ouverture du flux, le système fournit une sorte de curseur qui peut "se balader" dans le fichier. Normalement, il se situe au début du fichier, et avance au fur et à mesure (si on lit un caractère, il se déplace sur le suivant) mais on peut aussi le "forcer" à se déplacer tout seul (pour lire, par exemple, la dernière phrase d'un texte sans toutes les lire).

Note : stdio.h doit être inclus.

Ouverture d'un flux

Lors de l'ouverture du flux (du fichier), il faut bien sûr connaître le nom ainsi que le chemin d'accès du fichier. Il faut indiquer au système s'il s'agit d'une lecture (auquel cas le fichier doit bien sûr exister), d'une écriture (il faut alors avoir le droit de le faire, c'est à dire que le fichier ne soit pas déjà ouvert par un autre programme) ou d'une création (qui revient à une écriture, mais dans un nouveau flux). Il faut aussi indiquer s'il s'agit d'un fichier texte (chaque "fragment" du fichier est séparé par un retour chariot) ou d'un fichier binaire (traité octet par octet).

La fonction utilisée est fopen (comme file open). Sa syntaxe est la suivante :

FILE *pfile;

pfile=fopen(<nom du fichier>,<type d'ouverture>);

fopen renvoie un pointeur sur le flux. En cas de problème, le pointeur vaut NULL (0). Il ne faut alors ni lire ni écrire dans ce flux, sous peine d'un plantage.

Le nom du fichier peut inclure le chemin d'accès (par exemple "c:\\windows\\win.ini") ou ne comporter que le nom ("win.ini", auquel cas le fichier doit se trouver dans le repertoire courant).

Le type de l'ouverture est une chaîne, dont voici les valeurs possibles :

Châine de type Signification Remarque
"rb" Lecture seule, mode binaire Le fichier doit exister. Seule la lecture est possible.
"rt" Lecture seule, mode texte Idem que plus haut mais en mode texte.
"wb" Ecriture seule, mode binaire Si un fichier de même nom existait, il est écrasé. Création de fichier.
"wt" Ecriture seule, mode texte Idem en mode texte
"r+t" Lecture/écriture, mode texte Le fichier doit exister, son contenu est mis à jour.
"r+b" Lecture/écriture, mode binaire Idem en mode binaire
"a+t" Ajout, mode texte Idem que "r+t" avec ajout en fin de fichier
"a+b" Ajout, mode binaire Idem en mode binaire

Par exemple, si l'on souhaire ouvrir pour lecture le fichier texte win.ini, situé dans le dossier Windows, on fait :

FILE *ptr;

ptr=fopen("c:\\windows\\win.ini","rt");

On peut ensuite lire son contenu.

Fermeture d'un flux

La fermeture est très simple : on utilise la fonction fclose()

fclose(ptr);

!!!! Un flux doit être refermé !!!!

Lecture dans un flux

On considère que le flux est ouvert, en lecture seule.

Mode texte

Le flux a donc été ouvert par ptr=fopen("fichier.tmp","rt");

On vérifie bien sûr que ptr n'est pas égal à NULL. Le pointeur se situe au début du fichier.

Pour lire un caractère seul, on utilise la fonction getc. Elle est similaire à la fonction getch, mais cherche le caractère dans le flux, non au clavier.

char c;

c=getc(ptr);

Le pointeur s'est déplacé d'un caractère et pointe vers le prochain. Mais lire un texte caractère par caractère est fastidieux. On peut alors lire ligne à ligne (une ligne se termine par un retour chariot) : c'est le rôle de la fonction fgets. Elle fonctionne comme gets, mais depuis un flux :

char s[120]; /* on reserve 120 caractères pour la chaîne. Mais si elle est plus longue, ça va planter : voir les problèmes de gets */

fgets(s,ptr); /* on lit la chaine */

Ligne à ligne ou lettre à lettre, c'est vous qui voyez. On peut aussi utiliser la lecture formattée (comme pour le clavier) par la fonction fscanf. Son utilisation, un peu complexe, ressemble à celle de scanf. Jetez-y un coup d'oeil.

Mode binaire

Dans ce mode, on lit le nombre d'objets que l'on veut, de la taille que l'on veut. C'est le mode le plus universel et le plus pratique. On ouvre le fichier par

ptr=fopen("fichier.tmp","rb");

En supposant bien sûr que ce fichier existe. On vérifie bien sûr que ptr ne vaut pas NULL, et on peut lire ce qu'on veut (on suppose évidemment que l'on sait comment est fait le fichier...).

Pour lire, on emploie la fonction fread. (pour file read). Sa syntaxe est :

fread(<pointeur destination>,<taille des objets>,<nombre d'objets>,<pointeur sur fichier>);

Elle renvoie le nombre d'objets lus. Sa syntaxe peut paraître difficile, mais c'est assez simple. Mettons que l'on souhaite lire un entier :

int i; /* l'entier que l'on va lire*/

fread(&i,sizeof(i),1,ptr);

Rappel : &i indique l'adresse de i, c'est donc un pointeur sur i.

sizeof() est une fonction C très pratique qui renvoie la taille, en octets, de l'objet indiqué. On a donc pas besoin de se rappeller qu'un int vaut 2 octets.

On ne lit qu'un entier, donc on l'indique : 1

On lit dans le flux pointé par ptr, on l'indique aussi.