Как работает ifstream eof()?
#include <iostream>
#include <fstream>
int main() {
std::fstream inf( "ex.txt", std::ios::in );
while( !inf.eof() ) {
std::cout << inf.get() << "\n";
}
inf.close();
inf.clear();
inf.open( "ex.txt", std::ios::in );
char c;
while( inf >> c ) {
std::cout << c << "\n";
}
return 0;
}
Я действительно запутался в функции eof()
. Предположим, что мой ex.txt контент:
abc
Он всегда читает дополнительный символ и показывает -1
при чтении с помощью eof()
. Но inf >> c
дал правильный результат, который был "abc"? Может ли кто-нибудь помочь мне объяснить это?
Ответы
Ответ 1
-1 - это get
способ сказать, что вы достигли конца файла. Сравните это с помощью std::char_traits<char>::eof()
(или std::istream::traits_type::eof()
) - избегайте -1, это волшебное число. (Хотя другой бит немного подробный - вы всегда можете просто позвонить istream::eof
)
Флаг EOF устанавливается только после того, как чтение попытается прочитать за конец файла. Если у меня есть 3-байтовый файл, и я читаю только 3 байта, EOF false
, потому что я еще не пробовал читать конец файла. Хотя это кажется запутанным для файлов, которые обычно знают их размер, EOF неизвестен до тех пор, пока на некоторых устройствах, таких как трубы и сетевые сокеты, не будет прочитано чтение.
Второй пример работает как inf >> foo
всегда будет возвращать inf
, с побочным эффектом попытки что-то прочитать и сохранить его в foo
. inf
, в if
или while
, будет оцениваться до true
, если файл "хорош": никаких ошибок, нет EOF. Таким образом, когда сбой чтения, inf
эвакуируется до false
, и ваш цикл правильно прерывается. Однако возьмите эту общую ошибку:
while(!inf.eof()) // EOF is false here
{
inf >> x; // read fails, EOF becomes true, x is not set
// use x // we use x, despite our read failing.
}
Однако это:
while(inf >> x) // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}
Это то, что мы хотим.
Ответ 2
iostream не знает его в конце файла, пока он не попытается прочитать этот первый символ за концом файла.
пример кода на cplusplus.com говорит, чтобы сделать это следующим образом: (Но вы не должны делать это таким образом)
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
}
Лучшая идиома - переместить чтение в условие цикла, например:
(Вы можете сделать это со всеми операциями чтения istream
, которые возвращают *this
, включая оператор >>
)
char c;
while(is.get(c))
cout << c;
Ответ 3
Флаг EOF устанавливается только после того, как операция чтения пытается прочесть конец файла. get()
возвращает символическую константу traits::eof()
(которая только что равна -1), поскольку она достигла конца файла и не могла читать больше данных, и только в этой точке будет eof()
быть истинным. Если вы хотите проверить это условие, вы можете сделать что-то вроде следующего:
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
Ответ 4
eof() проверяет eofbit в состоянии потока.
В каждой операции чтения, если позиция находится в конце потока, и необходимо считывать больше данных, eofbit устанавливается в значение true. Поэтому вы получите дополнительный символ, прежде чем вы получите eofbit = 1.
Правильный способ - проверить, было ли достигнуто eof (или, была ли выполнена операция чтения) после операции чтения. Это то, что делает ваша вторая версия - вы выполняете операцию чтения, а затем используете результирующую ссылку на объект потока (которая возвращается) в качестве логического значения, что приводит к проверке на fail().