Fonctions de bibliothèque C -feof()
Bibliothèque standard C - <stdio.h>
feof()Utilisée pour détecter si le fichier a déjà été lu jusqu'à la fin.
On peut le considérer comme un « détecteur de fin » — chaque fois que vous finissez de lire une partie du contenu, vous lui demandez : « Avons-nous atteint la fin ? »
Description
Fonctions de bibliothèque Cint feof(FILE *stream)Teste l'indicateur de fin de fichier du flux donné.
Deux nouveaux concepts apparaissent ici ; laissez-moi d'abord les expliquer séparément :
fluxC'est une abstraction des entrées/sorties en langage C. Qu'il s'agisse d'un fichier sur un disque dur, d'une saisie au clavier ou de données réseau, en C, tout est uniformément traité comme un « flux ». Vous pouvez imaginer un flux comme un tuyau d'eau, avec les données circulant d'une extrémité à l'autre.
Indicateur de fin de fichier (marqueur EOF)C'est un indicateur d'état interne porté par chaque flux de fichier. Il est comme un signet qui se tourne automatiquement vers la page « fin de lecture » lorsque le contenu du fichier a été entièrement lu.
Le but de feof() est de vérifier ce signet — si le signet indique « fin de lecture », feof() renvoie une valeur non nulle. Si le signet est encore à « lecture non terminée », feof() renvoie 0.
Déclaration
Voici la déclaration de la fonction feof() ; décomposons sa signification partie par partie :
int feof(FILE *stream)
intC'est le type de retour — feof() renvoie un entier ; non nul signifie que la fin a été atteinte, 0 signifie qu'elle ne l'a pas été.
FILE *streamCeci est le paramètre — vous devez passer un pointeur de fichier (le pointeur renvoyé par fopen() lors de l'ouverture du fichier) pour indiquer à feof() quel flux de fichier vérifier.
Paramètre
feof() prend un paramètre :
| Paramètre | Type | Description |
|---|---|---|
| flux | FILE * | Pointeur de fichier, renvoyé par la fonction fopen(), pointant vers le fichier ouvert à vérifier. |
Valeur de retour
La valeur de retour est décrite comme suit :
| Valeur de retour | Signification |
|---|---|
| valeur non nulle | Le fichier a été lu jusqu'à la fin ; il n'y a plus de contenu à lire. |
| 0 | Le fichier n'a pas encore été entièrement lu, la lecture peut donc continuer |
Point clé : feof() ne renvoie une valeur non nulle qu'après « avoir tenté de lire au-delà de la fin du fichier ». Si vous venez de lire le dernier caractère mais que vous n'avez pas encore essayé de continuer la lecture, feof() renvoie toujours 0. Ce problème de timing sera expliqué en détail dans la section suivante.
Exemple
L'exemple suivant montre l'utilisation correcte de la fonction feof().
Le programme lit le contenu du fichier caractère par caractère, et chaque fois qu'il lit un caractère, il utilise feof() pour vérifier si la fin a été atteinte.
Exemple
int main ()
{
// FILE * est un type de pointeur de fichier, utilisé pour pointer vers un fichier ouvert
FILE *fp;
// fgetc() renvoie int au lieu de char, car il peut avoir besoin de renvoyer EOF (-1)
int c;
// fopen() ouvre un fichier, "r" indique le mode lecture seule (lecture)
fp = fopen("file.txt","r");
// Si le fichier n'existe pas ou si la permission est refusée, fopen() renvoie NULL
if(fp == NULL)
{
// perror() affiche les messages d'erreur système pour aider à localiser le problème
perror("Error opening file");
return(-1);
}
// Utilisez une boucle infinie + des vérifications internes
// Cela garantit de "lire d'abord, puis vérifier", ce qui évite de lire du contenu supplémentaire
while(1)
{
// Étape 1 : Lire un caractère depuis le fichier
c = fgetc(fp);
// Étape 2 : Immédiatement après la lecture, utilisez feof() pour vérifier si la fin a été atteinte
if( feof(fp) )
{
// Si la fin est atteinte, sortez de la boucle et arrêtez de traiter c
break ;
}
// Étape 3 : N'utilisez la valeur de c qu'après avoir confirmé que la fin n'a pas été atteinte
printf("%c", c);
}
// fclose() ferme le fichier et libère les ressources système
fclose(fp);
return(0);
}
Supposons que nous ayons un fichier textefile.txt, dont le contenu est le suivant :
这里是 example.com
Compilez et exécutez le programme ci-dessus, la sortie est :
这里是 example.com
Le programme a correctement imprimé tout le contenu du fichier, sans aucun caractère parasite supplémentaire.
Piège courant : pourquoi vous ne pouvez pas mettre feof() dans la condition de boucle
De nombreux débutants écrivent le style de code suivant, qui semble plus concis, mais qui est en réalité incorrect :
Exemple incorrect
int main ()
{
FILE *fp;
int c;
fp = fopen("file.txt","r");
if(fp == NULL)
{
perror("Error opening file");
return(-1);
}
// Incorrect : utiliser feof() comme condition d'entrée de boucle
while( !feof(fp) )
{
c = fgetc(fp);
printf("%c", c);
}
fclose(fp);
return(0);
}
La sortie de ce code incorrect serait :
这里是 example.com
Il y a un caractère parasite supplémentaire à la fin. Pourquoi cela ? Traçons ci-dessous le processus d'exécution de la boucle, tour à tour :
| Itérations de la boucle | Entrée de boucle feof() | fgetc() lit | Sorties de printf() | Description |
|---|---|---|---|---|
| Tour 1 | Renvoie 0 (pas encore lu) | '这' | 这 | normal |
| Tour 2 | Renvoie 0 (pas encore à la fin) | '里' | 里 | normal |
| ... | ... | ... | ... | Les caractères du milieu s'affichent normalement |
| Dernier tour | Renvoie 0 (pas encore à la fin) | 'm' | m | Le dernier caractère normal |
| Un tour supplémentaire | Renvoie 0 (Remarque ! À ce stade, 'm' vient d'être lu, et feof ne sait pas encore que la fin a été atteinte.) | EOF(-1) | (caractères illisibles) | Bug ! Lecture une fois de trop |
La racine du problème est la suivante : lorsque vous venez de lire 'm' (le dernier caractère du fichier), feof() renvoie encore 0.
Il doit attendre que vous « essayiez de lire une fois de plus » et découvriez qu'il n'y a plus de contenu à lire, et c'est seulement alors qu'il fera basculer le drapeau interne sur « terminé ».
Donc le motif while(!feof(fp)) fait exécuter à la boucle une itération supplémentaire. Dans cette itération supplémentaire, fgetc() renvoieEOF(-1), printf tente d'imprimer -1 comme un caractère, ce qui produit une sortie brouillée.
Une phrase à retenir :feof() est un « rapport après coup », pas un « avertissement préalable »EOF. Il répond à « si la fin a été atteinte lors de la dernière lecture », et non à « si la fin sera atteinte lors de la prochaine lecture ». N'utilisez donc jamais feof() comme condition d'entrée d'une boucle.
Le bon motif est l'approche de l'exemple précédent : lire d'abord, puis vérifier, et n'utiliser le contenu lu qu'après avoir confirmé qu'il est sûr.
Quand utiliser feof()
feof() est principalement utilisé dans les deux scénarios suivants :
| Scénarios | Utilisation | Exemple |
|---|---|---|
| Lire un fichier dans une boucle | Lire d'abord, puis vérifier (recommandé) | while(1) { c = fgetc(fp); if(feof(fp)) break; ... } |
| Dépannage des erreurs de lecture | Distinguer entre « arrêt normal » et « erreur de lecture » | if(feof(fp)) { /* lecture terminée normalement */ } else if(ferror(fp)) { /* erreur de lecture */ } |
Dans le second scénario, le retour de EOF par fgetc() a deux possibilités : soit le contenu a réellement été entièrement lu (déterminé avec feof()), soit une erreur s'est produite pendant la lecture (déterminée avec ferror()). Il faut distinguer les deux et les traiter séparément.
autres extensions