Un fichier texte est un ensemble de caractères se trouvant sur un support externe (donc pas en mémoire) et structuré au niveau logique en lignes de longueurs variables (au niveau physique, il y a simplement des caractères de fin de ligne).
Les deux traitements fondamentaux que l’on effectue sur les fichiers textes sont :
- la lecture séquentielle : on lit les caractères ou les lignes dans l’ordre où ils se trouvent. Le fichier est alors un flot d’entrée du programme.
- L’écriture séquentielle : on écrit des caractères ou des lignes en les plaçant bout à bout dans le fichier. Le fichier est alors un flot de sortie du programme.
En C, les définitions sur les fichiers se trouvent dans stdio.h
Le type FILE
En C, le type FILE est le type fichier qui est utilisé via des pointeurs.
FILE *fic ;
déclare un pointeur sur fichier.
Ouverture d’un
fichier
La fonction fopen permet d’ouvrir un fichier, ce qui est nécessaire avant d’effectuer toute opération.
fopen(nomfic,mode)
nomfic est une chaîne de caractères qui est le nom du fichier pour le système d’exploitation ;
mode est une chaîne de caractères qui précise comment le fichier doit être ouvert ;
Le résultat est NULL si le fichier n’a pas pu être ouvert ; c’est un pointeur sur FILE s’il a été ouvert.
Les valeurs fondamentales de mode sont :
"r" : ouverture en lecture (read). Le fichier doit exister, son contenu n’est pas détruit, le descripteur se place au début. Seules les opérations de lecteur sont autorisées.
"w" : ouverture en écriture (write). Le fichier ne doit pas nécessairement exister. S’il existe, son contenu est détruit, le descripteur se place au début (le fichier est vide). Seules les opérations d’écriture sont autorisées.
"a" : ouverture en allongement (append). Le fichier ne doit pas nécessairement exister. S’il existe, son contenu n’est pas détruit, le descripteur se place à la fin. Seules les opérations d’écriture sont autorisées.
Sauf situation particulière, l’ouverture d’un fichier lui associe un tampon (buffer) qui est un espace de la mémoire contenant une partie des informations du fichier et ayant pour but d’accélérer les opérations effectuées sur le fichier.
Fermeture d’un
fichier
La fonction fclose permet de fermer un fichier, ce qui est nécessaire quand on a terminé d’effectuer les opérations sur ce fichier.
close(fic)
fic est un pointeur sur fichier qui a été obtenu par un fopen n’ayant pas échoué.
La fonction rend 0 en cas de succès, une autre valeur en cas d’échec.
Ne pas fermer un fichier ouvert en lecture n’a en général pas d’effet.
Ne pas fermer un fichier ouvert en écriture peut faire perdre une partie, voire l’intégralité, du fichier.
Ecriture par fprintf
fprintf est analogue à printf avec un argument complémentaire, le premier, qui indique dans quel fichier on écrit.
fprintf(fic, format, e1, e2…)
écrit dans le fichier fic les valeurs des expressions e1, e2… avec le format format à la suite.
Rend le nombre de caractères écrits, un nombre négatif en cas d’erreur.
Schéma classique
d’écriture d’un fichier ligne par ligne
FILE *fic;
fic = fopen("MonFichier.txt","w");
if (fic == NULL)
printf("Le fichier MonFichier.txt n'a pas ete cree");
else
{
while ( <test de continuité du traitement> )
{
< construction d’une chaîne ch à écrire dans le fichier
sur une ligne >
fprintf(fic,"%s\n",ch);
}
fclose(fic);
}
Lecture par fscanf
fscanf est analogue à scanf avec un argument complémentaire, le premier, qui indique dans quel fichier on lit.
fscanf(fic, format, &e1, &e2…)
lit depuis le fichier fic les valeurs suivantes et les affecte aux variables e1, e2… avec le format format.
Rend un entier qui est le nombre d’expressions lues ou EOF s’il y a eu erreur.
EOF signifie End Of File. En C, c’est un entier négatif.
Schéma classique de
lecture d’un fichier ligne par ligne
FILE *fic;
fic = fopen("MonFichier.txt","r");
if (fic == NULL)
printf("Le fichier MonFichier.txt n'a pas ete ouvert");
else
{
while (1)
{
if (fscanf(fic,"%s",&ch) == EOF)
break;
< traitement de ch >
}
fclose(fic);
}
à Attention : les espaces et les tabulations arrêtent la lecture (comme les fins de lignes). Si l’on veut une vraie lecture de ligne, prendre la fonction fgets.
#define NN 255
...
Char ch[NN] ;
...
while (1)
{
if (fgets(ch,
NN, fic) == NULL)
break;
< traitement de ch >
}
Les flots standard en
C
En mode console, le clavier et l’écran sont des flots.
C possède 3 flots standard qui sont ouverts dès le lancement du programme et n’ont pas besoin d’être fermés :
stdin : standard input, en fonctionnement classique, c’est le clavier, pour lire des informations au clavier.
stdout : standard output, en fonctionnement classique,
c’est l’écran, pour écrire des informations à l’écran.
stderr : standard error, en fonctionnement classique, c’est l’écran, pour écrire des messages d’erreur.
printf(format, e1, e2…)
est équivalent à :
fprintf(stdout, format, e1, e2…)
scanf(format, e1, e2…)
est équivalent à :
fscanf(stdin, format, e1, e2…)
En mode console, sur certains systèmes (Unix, MS-DOS) on peut, au lancement du programme, remplacer stdin par un fichier texte ou stdout par un fichier texte ou faire les deux.
monProgramme < fic1.txt
lance monProgramme avec fic1.txt à la place de stdin. Les lectures au clavier sont remplacées par des lectures dans fic1.
monProgramme > fic2.txt
lance monProgramme avec fic2.txt à la place de stdout. Les
écritures à l’écran sont remplacées par des écritures dans fic2.
monProgramme < fic1.txt > fic2.txt
lance monProgramme avec fic1.txt à la place de stdin et fic2.txt à la place de stdout.
On peut enchaîner deux programmes, faire en sorte que les sorties de l’un (sur stdout) soient les entrées de l’autres (sur stdin), exemple :
prog1 | prog2
prog1 lit au clavier et écrit dans le flot d’entrée de prog2
prog2 lit dans le flot de sortie de prog1 et écrit à l’écran.
Autre exemple :
prog1 < fic1.txt | prog2 > fic2.txt
prog1 lit dans fic1.txt et écrit dans le flot d’entrée de prog2
prog2 lit dans le flot de sortie de prog1 et écrit dans fic2.txt
Autres fonctions
d’entrées sorties
feof(fic)
Renvoie une valeur non nulle si l’on est en fin de fichier, 0 si l’on n’y est pas.
fputc(car,fic)
écrit le caractère car dans le fichier fic. Revoie le caractère écrit ou EOF s’il y a eu erreur.
putchar(car)
analogue a fputc pour stdout
fputs(ch,fic)
écrit la chaine ch dans le fichier fic. Revoie EOF s’il y a eu erreur, une valeur positive dans les autres cas. fputs ne met pas le caractère de fin de ligne, il faut le mettre soi-même. Il peut être plus facile d’utiliser fprintf pour cela.
puts(ch)
analogue a fputs pour stdout
fgetc(fic)
Revoie le caractère suivant de fic ou EOF s’il y a eu erreur ou si la fin du fichier est atteinte.
getchar()
analogue à fgetc pour stdin
fgets(s, n, fic)
Lecture d’une ligne de fic dans la chaîne s en se limitant à n-1 caractères.
Le caractère de fin de ligne '\n' est copié dans le tableau et un '\0' est mis ensuite.
Renvoie s ou NULL en cas d’erreur ou de fin de fichier.
gets(s)
analogue à fgets pour stdin mais sans contrôle du nombre de caractères et en remplaçant la fin de ligne par '\0'.
sprintf(ch, format, &e1, &e2…)
analogue à fprintf mais le
résultat est mis dans la chaîne ch
sscanf(ch, format, &e1, &e2…)
analogue à fscanf mais le résultat est extrait de la chaîne ch
Enregistrement au
format csv simplifié
Cela consiste à écrire des structures à raison d’une par ligne, les champs étant séparés par des « ; ». Il faut qu’il n’y ait pas de « ; » et pas de « " » dans les champs à écrire.
Exemple d’écriture d’une liste de personnes
void EnregistrerLaListe(LISTE_PERSONNE l)
{
FILE *fic;
char nomfic[20];
printf("\nNom du fichier : ");
scanf("%s",&nomfic);
fic = fopen(nomfic,"w");
if (fic == NULL)
printf("Le fichier %s n'a pas ete cree",nomfic);
else
{
while (l != NULL)
{
fprintf(fic,"%s;%s;%d\n",l->nom,l->prenom,l->age);
l = l->suivant;
}
fclose(fic);
}
}
Exemple de lecture d’une liste
de personnes
Ici, on lit ce format ligne par ligne avec fgets et on extrait les champs de la chaîne avec une procédure que l’on écrit pour cela.
/* extrait de s les caractères allant jusqu'au premier ";"
les place dans champ et les enlève de s
rend champ */
void champ_suiv(char *s, char *champ)
{
char *s1, *c1, *s2;
/* on extrait */
s1 = s; /* pointe sur l'endroit à traiter */
c1 = champ; /* pointe sur l'endroit à remplir */
while (*s1 != '\0' && *s1 != ';')
{
if (*s1 >= ' ') /* on ne prend pas les caractères de contrôle */
*c1++ = *s1;
s1++;
}
*c1 = '\0';
/* on décale */
if (*s1 == ';')
s1++;
s2 = s; /* pointe sur l'endroit à remplir */
while (*s1 != '\0')
{
if (*s1 >= ' ') /* on ne prend pas les caractères de contrôle */
*s2++ = *s1;
s1++;
}
*s2 = '\0';
}
/* ----------------------------------------------------
On charge la liste à partir d'un fichier dont on saisit le nom
Il y a une information par ligne
S'il n'y a pas tous les champs pour une personne, on l'ignore
On rend la liste chargée
------------------------------------------------------*/
LISTE_PERSONNE ChargerListe()
{
FILE *fic;
char nomfic[20], ch[256], champ[256];
LISTE_PERSONNE l, lp;
lp = NULL;
printf("\nNom du fichier : ");
scanf("%s",&nomfic);
fic = fopen(nomfic,"r");
if (fic == NULL)
printf("Le fichier %s n'a pas ete ouvert",nomfic);
else
{
while (fgets(ch, 256, fic) != NULL)
{
l = malloc(sizeof(CEL_LISTE_PERSONNE));
champ_suiv(ch,champ);
strcpy(l->nom,champ);
champ_suiv(ch,champ);
strcpy(l->prenom,champ);
champ_suiv(ch,champ);
l->age = atoi(champ);
l->suivant = lp;
lp = l;
}
fclose(fic);
lp = inverse(lp);
}
return lp;
}
Exemple de lecture d’une liste
de personnes
Ici, on lit ce format champ par champ avec une fonction que l’on écrit et qui lit le fichier caractère par caractère.
/* ----------------------------------------------------
On lit un champ dans le fichier f
On rend le caractère d'arrêt de la lecture ';' ou '\n' ou EOF
------------------------------------------------------*/
char getchamp(FILE *f, char *champ, int n)
{
char c;
int i = 0;
c = fgetc(f);
while (c != EOF && c != '\n' && c != ';')
{
if (i < n-1)
champ[i++] = c;
c = fgetc(f);
}
champ[i] = '\0';
return c;
}
/* ----------------------------------------------------
On lit jusqu'à renconter '\n' ou EOF
On rend le dermier caractère lu
------------------------------------------------------*/
char finirligne(FILE *f)
{
char c;
c = fgetc(f);
while (c != EOF && c != '\n')
c = fgetc(f);
return c;
}
/* ----------------------------------------------------
On charge la liste à partir d'un fichier dont on saisit le nom
Il y a une personne par ligne, les champs sont séparés par des ";"
On lit par champ avec la fonction getchamp
------------------------------------------------------*/
LISTE_PERSONNE ChargerListeParChamp()
{
FILE *fic;
char nomfic[20], car, s_age[20];
LISTE_PERSONNE l, lp;
lp = NULL;
printf("\nNom du fichier : ");
scanf("%s",&nomfic);
fic = fopen(nomfic,"r");
if (fic == NULL)
printf("Le fichier %s n'a pas ete ouvert",nomfic);
else
{
if (feof(fic))
car = EOF;
else car = '\n';
while (car != EOF)
{
l = malloc(sizeof(CEL_LISTE_PERSONNE));
/* valeurs par défaut */
strcpy(l->nom,"");
strcpy(l->prenom,"");
l->age = 0;
car = getchamp(fic, l->nom, 20);
if (car != EOF && car != '\n')
car = getchamp(fic, l->prenom, 20);
if (car != EOF && car != '\n')
{
car = getchamp(fic, s_age, 20);
if (s_age != "")
l->age = atoi(s_age);
}
if (car != EOF && car != '\n')
car = finirligne(fic);
if (strlen(l->nom) == 0)
free(l);
else
{
l->suivant = lp;
lp = l;
}
}
fclose(fic);
lp = inverse(lp);
}
return lp;
}
Format csv non
simplifié
S’il y a des « ; » dans un champ, on l’écrit entouré de guillemets.
ab;cd s’écrit "ab;cd"
S’il y a des « " » dans un champ, on l’écrit entouré de guillemets et on double les guillemets du champ.
ab"cd s’écrit "ab""cd"
Cela complique un peu les fonctions de lecture et d’écriture, mais permet de tout écrire et de tout relire.