C-Bibliotheksfunktionen -feof()
C-Standardbibliothek - <stdio.h>
feof()Wird verwendet, um festzustellen, ob die Datei bereits bis zum Ende gelesen wurde.
Man kann es sich als einen "Enddetektor" vorstellen – jedes Mal, wenn man einen Teil des Inhalts gelesen hat, fragt man ihn: "Haben wir das Ende erreicht?"
Beschreibung
C-Bibliotheksfunktionenint feof(FILE *stream)Testet den End-of-File-Indikator des angegebenen Streams.
Hier tauchen zwei neue Konzepte auf; ich erkläre sie zuerst einzeln:
StreamEr ist eine Abstraktion der Ein-/Ausgabe in der C-Sprache. Ob es sich um eine Datei auf einer Festplatte, eine Tastatureingabe oder Netzwerkdaten handelt, in C wird alles einheitlich als "Stream" behandelt. Man kann sich einen Stream wie ein Wasserrohr vorstellen, bei dem Daten von einem Ende zum anderen fließen.
End-of-File-Indikator (EOF-Marker)Er ist ein internes Status-Flag, das jeder Datei-Stream trägt. Er ist wie ein Lesezeichen, das automatisch auf die Seite "Fertig gelesen" umblättert, wenn der Dateiinhalt vollständig gelesen wurde.
Der Zweck von feof() ist es, dieses Lesezeichen zu prüfen – wenn das Lesezeichen "Fertig gelesen" anzeigt, gibt feof() einen Wert ungleich null zurück. Wenn das Lesezeichen noch auf "Nicht fertig gelesen" steht, gibt feof() 0 zurück.
Deklaration
Unten sehen Sie die Deklaration der Funktion feof(); zerlegen wir ihre Bedeutung Teil für Teil:
int feof(FILE *stream)
intDies ist der Rückgabetyp – feof() gibt eine Ganzzahl zurück; ungleich null bedeutet, dass das Ende erreicht wurde, 0 bedeutet, dass es nicht erreicht wurde.
FILE *streamDies ist der Parameter — Sie müssen einen Dateizeiger übergeben (den Zeiger, der von fopen() beim Öffnen der Datei zurückgegeben wird), um feof() mitzuteilen, welcher Dateistream überprüft werden soll.
Parameter
feof() akzeptiert einen Parameter:
| Parameter | Type | Beschreibung |
|---|---|---|
| stream | FILE * | Dateizeiger, zurückgegeben von der Funktion fopen(), der auf die geöffnete Datei zeigt, die überprüft werden soll. |
Rückgabewert
Der Rückgabewert wird wie folgt beschrieben:
| Rückgabewert | Bedeutung |
|---|---|
| Nicht-Null-Wert | Die Datei wurde bis zum Ende gelesen; es gibt keinen weiteren Inhalt mehr zu lesen. |
| 0 | Die Datei wurde noch nicht vollständig gelesen, daher kann das Lesen fortgesetzt werden |
Wichtiger Punkt: feof() gibt erst dann einen Nicht-Null-Wert zurück, nachdem „versucht wurde, über das Ende der Datei hinaus zu lesen“. Wenn Sie gerade das letzte Zeichen gelesen haben, aber noch nicht versucht haben, weiterzulesen, gibt feof() immer noch 0 zurück. Dieses Timing-Problem wird im nächsten Abschnitt ausführlich erklärt.
Beispiel
Das folgende Beispiel demonstriert die korrekte Verwendung der Funktion feof().
Das Programm liest den Dateiinhalt Zeichen für Zeichen und verwendet jedes Mal, wenn es ein Zeichen liest, feof(), um zu prüfen, ob das Ende erreicht wurde.
Beispiel
int main ()
{
// FILE * ist ein Dateizeiger-Typ, der verwendet wird, um auf eine geöffnete Datei zu zeigen
FILE *fp;
// fgetc() gibt int statt char zurück, weil es möglicherweise EOF (-1) zurückgeben muss
int c;
// fopen() öffnet eine Datei, "r" steht für den Nur-Lese-Modus (Lesen)
fp = fopen("file.txt","r");
// Wenn die Datei nicht existiert oder die Berechtigung verweigert wird, gibt fopen() NULL zurück
if(fp == NULL)
{
// perror() gibt Systemfehlermeldungen aus, um das Problem leichter zu lokalisieren
perror("Fehler beim Öffnen der Datei");
return(-1);
}
// Verwende eine Endlosschleife + interne Prüfungen
// Dies gewährleistet "erst lesen, dann prüfen", wodurch das Lesen zusätzlicher Inhalte vermieden wird
while(1)
{
// Schritt 1: Ein Zeichen aus der Datei lesen
c = fgetc(fp);
// Schritt 2: Direkt nach dem Lesen mit feof() prüfen, ob das Ende erreicht wurde
if( feof(fp) )
{
// Wenn das Ende erreicht ist, die Schleife verlassen und die Verarbeitung von c beenden
break ;
}
// Schritt 3: Den Wert von c erst verwenden, nachdem bestätigt wurde, dass das Ende nicht erreicht ist
printf("%c", c);
}
// fclose() schließt die Datei und gibt Systemressourcen frei
fclose(fp);
return(0);
}
Angenommen, wir haben eine Textdateifile.txt, deren Inhalt wie folgt aussieht:
这里是 example.com
Kompiliere und führe das obige Programm aus, die Ausgabe ist:
这里是 example.com
Das Programm hat den gesamten Dateiinhalt korrekt ausgegeben, ohne zusätzliche unleserliche Zeichen.
Häufige Falle: Warum man feof() nicht in die Schleifenbedingung setzen darf
Viele Anfänger schreiben den folgenden Codestil, der kürzer aussieht, aber tatsächlich falsch ist:
Falsches Beispiel
int main ()
{
FILE *fp;
int c;
fp = fopen("file.txt","r");
if(fp == NULL)
{
perror("Fehler beim Öffnen der Datei");
return(-1);
}
// Falsch: feof() als Schleifen-Eintrittsbedingung verwenden
while( !feof(fp) )
{
c = fgetc(fp);
printf("%c", c);
}
fclose(fp);
return(0);
}
Die Ausgabe dieses falschen Codes wäre:
这里是 example.com
Am Ende gibt es ein zusätzliches unleserliches Zeichen. Warum ist das so? Verfolgen wir unten den Ausführungsprozess der Schleife Runde für Runde:
| Schleifeniterationen | Schleifeneintritt feof() | fgetc() liest | printf()-Ausgaben | Beschreibung |
|---|---|---|---|---|
| Runde 1 | Gibt 0 zurück (noch nicht gelesen) | '这' | 这 | normal |
| Runde 2 | Gibt 0 zurück (noch nicht am Ende) | '里' | 里 | normal |
| ... | ... | ... | ... | Mittlere Zeichen werden normal ausgegeben |
| Letzte Runde | Gibt 0 zurück (noch nicht am Ende) | 'm' | m | Das letzte normale Zeichen |
| Eine zusätzliche Runde | Gibt 0 zurück (Hinweis! Zu diesem Zeitpunkt wurde gerade 'm' gelesen, und feof weiß noch nicht, dass das Ende erreicht wurde.) | EOF(-1) | (Zeichensalat) | Bug! Einmal zu viel gelesen |
Die Ursache des Problems ist: Wenn Sie gerade 'm' gelesen haben (das letzte Zeichen der Datei), gibt feof() immer noch 0 zurück.
Es muss warten, bis Sie "versuchen, noch einmal zu lesen" und feststellen, dass kein weiterer Inhalt zum Lesen vorhanden ist, und erst dann wird das interne Flag auf "beendet" umgesetzt.
Das Muster while(!feof(fp)) führt also dazu, dass die Schleife eine zusätzliche Iteration ausführt. In dieser zusätzlichen Iteration gibt fgetc()EOF(-1) zurück, printf versucht, -1 als Zeichen auszugeben, was zu verstümmelter Ausgabe führt.
Ein Satz zum Merken:feof() ist ein 'nachträglicher Bericht', keine 'Vorwarnung'EOF. Es beantwortet "ob das Ende während des letzten Lesevorgangs erreicht wurde", nicht "ob das Ende beim nächsten Lesevorgang erreicht wird". Verwenden Sie also niemals feof() als Eintrittsbedingung einer Schleife.
Das korrekte Muster ist der Ansatz im vorherigen Beispiel – zuerst lesen, dann prüfen und den gelesenen Inhalt erst verwenden, nachdem bestätigt wurde, dass er sicher ist.
Wann feof() verwendet werden sollte
feof() wird hauptsächlich in den folgenden zwei Szenarien verwendet:
| Szenarien | Nutzung | Beispiel |
|---|---|---|
| Datei in einer Schleife lesen | Zuerst lesen, dann prüfen (Empfohlen) | while(1) { c = fgetc(fp); if(feof(fp)) break; ... } |
| Fehlerbehebung bei Lesefehlern | Unterscheidung zwischen "normaler Beendigung" und "Lesefehler" | if(feof(fp)) { /* Lesen normal abgeschlossen */ } else if(ferror(fp)) { /* Lesefehler */ } |
Im zweiten Szenario hat die Rückgabe von EOF durch fgetc() zwei Möglichkeiten: Entweder wurde der Inhalt wirklich vollständig gelesen (festgestellt mit feof()), oder beim Lesen ist ein Fehler aufgetreten (festgestellt mit ferror()). Die beiden müssen unterschieden und getrennt behandelt werden.
Weitere Erweiterungen