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:

ParameterTypeBeschreibung
streamFILE *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ückgabewertBedeutung
Nicht-Null-WertDie Datei wurde bis zum Ende gelesen; es gibt keinen weiteren Inhalt mehr zu lesen.
0Die 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

#include <stdio.h>

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

#include <stdio.h>

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:

SchleifeniterationenSchleifeneintritt feof()fgetc() liestprintf()-AusgabenBeschreibung
Runde 1Gibt 0 zurück (noch nicht gelesen)'这'这normal
Runde 2Gibt 0 zurück (noch nicht am Ende)'里'里normal
............Mittlere Zeichen werden normal ausgegeben
Letzte RundeGibt 0 zurück (noch nicht am Ende)'m'mDas letzte normale Zeichen
Eine zusätzliche RundeGibt 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:

SzenarienNutzungBeispiel
Datei in einer Schleife lesenZuerst lesen, dann prüfen (Empfohlen)while(1) { c = fgetc(fp); if(feof(fp)) break; ... }
Fehlerbehebung bei LesefehlernUnterscheidung 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.

C-Standardbibliothek - <stdio.h>

Weitere Erweiterungen