Как работает ifstream eof ()? - PullRequest
       34

Как работает ifstream eof ()?

39 голосов
/ 26 декабря 2010
#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'?Кто-нибудь может мне помочь объяснить это?

Ответы [ 4 ]

67 голосов
/ 26 декабря 2010

-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.
}

Что мы и хотим.

7 голосов
/ 26 декабря 2010

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;
7 голосов
/ 26 декабря 2010

Флаг EOF устанавливается только после того, как операция чтения пытается прочитать после конца файла. get() возвращает символическую константу traits::eof() (которая просто равна -1), потому что она достигла конца файла и не может прочитать больше данных, и только в этот момент eof() будет истинным. Если вы хотите проверить это условие, вы можете сделать что-то вроде следующего:

int ch;
while ((ch = inf.get()) != EOF) {
    std::cout << static_cast<char>(ch) << "\n";
}
2 голосов
/ 26 декабря 2010

eof () проверяет eofbit в состоянии потока.

При каждой операции чтения, если позиция находится в конце потока и необходимо прочитать больше данных, eofbit устанавливается в значение true.Таким образом, вы получите дополнительный символ, прежде чем получите eofbit = 1.

Правильный способ - проверить, было ли достигнуто значение eof (или успешно выполнена операция чтения) после операция чтения.Это то, что делает ваша вторая версия - вы выполняете операцию чтения, а затем используете результирующую ссылку на объект потока (которая >> возвращает) в качестве логического значения, что приводит к проверке fail ().

...