Чому ifstream.eof () не повертає TRUE після прочитання останнього рядка файлу?


11

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

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

Однак, використовуючи цей код, я помітив, що він не зупинявся, поки не прочитав останній рядок файлу двічі. Програмісти на C ++ зазначають, що це насправді не те, як слід читати файл. Замість цього вони, як правило, рекомендують тому, хто має читати файл, замість цього використовувати цикл:

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

Чому перший фрагмент коду завжди не працює належним чином?


Я би подумав, що буде дублікат, але я не можу його знайти тут. Є багато дублікатів на stackoverflow.
Девід Хаммен

Відповіді:


4

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

Якщо останній рядок файлу закінчується символом нового рядка ( \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 як стан циклу. Умова циклу має виражати те, що ви намагаєтеся зробити, це (наприклад), витягування чисел із потоку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.