Почему ifstream.eof () не возвращает TRUE после чтения последней строки файла?

11

Когда новичок начинает читать ifstreams, его / ее инстинкт должен прочитать файл, используя цикл, который обычно выглядит следующим образом:

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

Однако, когда я использовал этот код, я заметил, что он не остановился, пока не прочитал последнюю строку файла дважды. Программисты C ++ отмечают, что на самом деле это не то, как нужно читать файл. Вместо этого они обычно рекомендуют, чтобы тот, кто должен прочитать файл, использовал цикл, подобный этому:

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

Почему первый кусок кода всегда не работает должным образом?

moonman239
источник
Я бы подумал, что будет дубликат, но я не могу найти его здесь. В стеке потока много дубликатов.
Дэвид Хаммен

Ответы:

4

while (!ifstream.eof())Цикл не работает, потому что потоки / файлы в C и C ++ не предсказать , когда вы достигли конца файла, а скорее указать , если вы пробовали читать мимо конца файла.

Если последняя строка файла заканчивается символом newline ( \n), то большинство действий чтения прекратят чтение, когда встретят этот символ, и не обнаружат, что это последний символ в файле. При следующем действии чтения может даже случиться так, что будет добавлено больше символов и что чтение сможет их извлечь.

Цикл с использованием оператора извлечения потока ( while (ifstream >> someVar)) работает, потому что результат от оператора извлечения потока оценивается как ложный, если он не может извлечь элемент правильного типа. Это также происходит, если не осталось символов для чтения.

Барт ван Инген Шенау
источник
4

Однако программисты на C ++ отмечают, что всегда происходит то, что cin.eof () не возвращает «true» до тех пор, пока последняя строка не будет прочитана дважды.

Это не то, что происходит. Игра не eofbitиграет никакой роли в преобразовании в логическое значение ( stream::operator bool(или operator void*в более старом c ++)). Только badbitи failbitучаствуют.

Предположим, вы читаете файл, содержащий числа, разделенные пробелами. Цикл, основанный вокруг cin.eof(), неизбежно будет либо неправильным, либо переполненным ifтестами. Вы не читаете до EOF. Вы читаете цифры. Сделайте так, чтобы ваш код выражал эту логику:

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

Это будет работать независимо от того, заканчивается ли последняя строка файла 0 42\nили 0 42нет (новой строки в конце последней строки в файле нет). Если файл заканчивается на 0 42\n, при последнем удачном прочтении будет получено значение 42 и будет считан последний маркер конца строки. Обратите внимание, что маркер EOF еще не прочитан. Функция process_valueвызывается с помощью 42. Следующий вызов оператора извлечения потока >> читает EOF, и, поскольку ничего не было извлечено, оба eofbitи failbitбудут установлены.

Предположим, с другой стороны, файл заканчивается на 0 42(без новой строки в конце последней строки). Последнее хорошее чтение извлечет значение 42, оканчивающееся на маркере EOF. Предположительно, вы хотите обработать это 42. Вот почему eofbitон не играет роли в операторе логического преобразования входного потока. При следующем вызове оператора извлечения потока >> базовый механизм быстро увидит, что eofbitон уже установлен. Это быстро приводит к настройке failbit.

Почему первый кусок кода всегда не работает должным образом?

Потому что вы не должны проверять EOF как условие цикла. Условие цикла должно выражать то, что вы пытаетесь сделать, например, извлечь числа из потока.

Дэвид Хаммен
источник