Kiedy początkujący zaczyna czytać strumienie, jego instynkt polega na czytaniu pliku za pomocą pętli, która zwykle wygląda następująco:
while (!ifstream.eof()
{
...
}
Kiedy jednak użyłem tego kodu, zauważyłem, że nie zatrzymał się, dopóki nie przeczytał dwukrotnie ostatniego wiersza pliku. Programiści C ++ zauważają, że tak nie powinno się czytać pliku. Zamiast tego zazwyczaj zalecają, aby ktokolwiek musiał odczytać plik, zamiast tego używał pętli:
while (ifstream >> someVar)
{
...
}
Dlaczego pierwszy fragment kodu zawsze nie działa poprawnie?
Odpowiedzi:
while (!ifstream.eof())
Pętla nie działa, ponieważ strumienie / pliki w C i C ++ nie przewidzieć, kiedy dotarły do końca pliku, lecz raczej wskazują jeśli próbowali odczytać przeszłość koniec pliku.Jeśli ostatni wiersz pliku kończy się znakiem nowej linii (
\n
), wówczas większość operacji odczytu przestanie czytać, gdy napotka ten znak i nie wykryje, że jest to ostatni znak w pliku. Przy następnej akcji odczytu może się zdarzyć, że dodano więcej znaków i że odczyt uda się je wyodrębnić.Pętla korzystająca z operatora ekstrakcji strumienia (
while (ifstream >> someVar)
) działa, ponieważ wynik operatora ekstrakcji strumienia został oceniony na false, jeśli nie można wyodrębnić elementu odpowiedniego typu. Dzieje się tak również, gdy nie ma już znaków do przeczytania.źródło
Tak się nie dzieje. Nie
eofbit
odgrywa żadnej roli w konwersji na wartość logiczną (stream::operator bool
(luboperator void*
starszą wersję c ++)). Zaangażowani są tylkobadbit
ifailbit
.Załóżmy, że czytasz plik zawierający liczby oddzielone spacjami. Pętla oparta na niej
cin.eof()
nieuchronnie będzie albo błędna, albo będzie pełnaif
testów. Nie czytasz do EOF. Czytasz cyfry. Niech twój kod wyrazi tę logikę:Działa to niezależnie od tego, czy ostatni wiersz pliku kończy się na,
0 42\n
czy tylko0 42
(nie ma nowego wiersza na końcu ostatniego wiersza w pliku). Jeśli plik kończy się na0 42\n
, ostatni dobry odczyt pobierze wartość 42 i odczyta znacznik końca linii. Zauważ, że znacznik EOF nie został jeszcze odczytany. Funkcjaprocess_value
jest wywoływana za pomocą42
. Następne wywołanie do operatora ekstrakcji strumienia >> czyta EOF, a ponieważ nic nie zostało wyodrębnione, ustawione zostaną zarównoeofbit
ifailbit
.Załóżmy z drugiej strony, że plik kończy się na
0 42
(brak nowej linii na końcu ostatniego wiersza). Ostatni dobry odczyt odzyska wartość 42 kończącą się na znaczniku EOF. Prawdopodobnie chcesz to przetworzyć 42. To dlategoeofbit
nie odgrywa roli w operatorze konwersji wartości logicznej strumienia wejściowego. Przy następnym wywołaniu do operatora wydobycia strumienia >> maszyna leżąca pod spodem szybko zauważy, żeeofbit
jest już ustawiony. To szybko powoduje ustawieniefailbit
.Ponieważ nie powinieneś sprawdzać EOF jako warunku pętli. Warunek pętli powinien wyrażać to, co próbujesz zrobić, czyli (na przykład) wyodrębnianie liczb ze strumienia.
źródło