Warum gibt ifstream.eof () nach dem Lesen der letzten Zeile einer Datei nicht TRUE zurück?

11

Wenn ein Anfänger anfängt, ifstreams zu lesen, besteht sein Instinkt darin, die Datei mit einer Schleife zu lesen, die normalerweise so aussieht:

while (!ifstream.eof()
{
...
}

Als ich diesen Code verwendete, bemerkte ich jedoch, dass er nicht aufhörte, bis er die letzte Zeile der Datei zweimal gelesen hatte. C ++ - Programmierer bemerken, dass man eine Datei nicht so lesen sollte. Stattdessen empfehlen sie normalerweise, dass jeder, der eine Datei lesen muss, stattdessen eine Schleife wie diese verwendet:

while (ifstream >> someVar)
{
...
}

Warum funktioniert der erste Code immer nicht richtig?

moonman239
quelle
Ich hätte gedacht, dass es ein Duplikat geben würde, aber ich kann hier keines finden. Es gibt viele Duplikate im Stapelüberlauf.
David Hammen

Antworten:

4

Die while (!ifstream.eof())Schleife funktioniert nicht, da Streams / Dateien in C und C ++ nicht vorhersagen, wann Sie das Ende der Datei erreicht haben, sondern eher angeben, ob Sie versucht haben, über das Ende der Datei hinaus zu lesen .

Wenn die letzte Zeile der Datei mit einem newline ( \n) -Zeichen endet , werden die meisten Leseaktionen nicht mehr gelesen, wenn sie auf dieses Zeichen gestoßen sind und nicht erkennen, dass es sich um das letzte Zeichen in der Datei handelt. Bei der nächsten Leseaktion kann es sogar sein, dass mehr Zeichen angehängt wurden und der Lesevorgang diese erfolgreich extrahieren kann.

Die Schleife, die den Stream-Extraktionsoperator ( while (ifstream >> someVar)) verwendet, funktioniert, weil das Ergebnis des Stream-Extraktionsoperators als falsch ausgewertet wird, wenn ein Element des richtigen Typs nicht extrahiert werden konnte. Dies geschieht auch, wenn keine Zeichen mehr zu lesen sind.

Bart van Ingen Schenau
quelle
4

C ++ - Programmierer bemerken jedoch, dass cin.eof () immer "true" zurückgibt, bis die letzte Zeile zweimal gelesen wurde.

Das ist nicht was passiert. Das eofbitspielt bei der Konvertierung in einen Booleschen Wert ( stream::operator bool(oder operator void*in älterem c ++)) keine Rolle . Nur die badbitund failbitsind beteiligt.

Angenommen, Sie lesen eine Datei mit durch Leerzeichen getrennten Zahlen. Eine Schleife, die auf basiert, cin.eof()ist unweigerlich entweder falsch oder voller ifTests. Sie lesen erst EOF. Sie lesen Zahlen. Lassen Sie Ihren Code diese Logik ausdrücken:

while (stream >> some_var) {
    process_value(some_var);
}

Dies funktioniert unabhängig davon, ob die letzte Zeile der Datei mit 0 42\noder nur endet 0 42(keine neue Zeile am Ende der letzten Zeile in der Datei). Wenn die Datei mit endet 0 42\n, ruft der letzte gute Lesevorgang den Wert 42 ab und liest den letzten Zeilenende-Marker. Beachten Sie, dass der EOF-Marker noch nicht gelesen wurde. Die Funktion process_valuewird mit aufgerufen 42. Der nächste Aufruf zum Stream-Operator >> liest den EOF, und da nichts extrahiert wurde, sowohl das eofbitund failbitwird eingestellt.

Angenommen, die Datei endet mit 0 42(keine neue Zeile am Ende der letzten Zeile). Der letzte gute Lesevorgang ruft den Wert 42 ab, der auf dem EOF-Marker endet. Vermutlich möchten Sie diese 42 verarbeiten. Aus diesem Grund eofbitspielt das im booleschen Konvertierungsoperator des Eingabestreams keine Rolle. Beim nächsten Aufruf an den Stream-Extraktionsoperator >> erkennt die zugrunde liegende Maschine schnell, dass der eofbitbereits eingestellt ist. Dies führt schnell zum Einstellen der failbit.

Warum funktioniert der erste Code immer nicht richtig?

Weil Sie nicht nach EOF als Schleifenbedingung suchen sollten. Die Schleifenbedingung sollte ausdrücken, was Sie versuchen, z. B. Zahlen aus einem Stream zu extrahieren.

David Hammen
quelle