Подтвердить что ты не робот

Как работает 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"? Может ли кто-нибудь помочь мне объяснить это?

4b9b3361

Ответ 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().