Сведения о вопросе

CPdeveloper

21:06, 1st October, 2020

Теги

c++   iostream   fstream    

Чтение из текстового файла до EOF повторяет последнюю строку

Просмотров: 531   Ответов: 7

Следующий код C++ использует объект ifstream для чтения целых чисел из текстового файла (который имеет одно число в строке), пока он не достигнет EOF . Почему он читает целое число в последней строке дважды? Как это исправить?

Код:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

input.txt :

10  
20  
30

Выход :

10  
20  
30  
30

Примечание: Я пропустил весь код проверки ошибок, чтобы сохранить небольшой фрагмент кода. Вышеописанное поведение наблюдается на Windows (Visual C++), cygwin (gcc) и Linux (gcc).



  Сведения об ответе

darknet

23:05, 17th August, 2020

Просто внимательно следите за цепочкой событий.

  • Возьмите 10
  • Возьмите 20
  • Возьмите 30
  • Возьмите EOF

Посмотрите на итерацию second-to-last. Вы схватили 30, а затем продолжили проверять на EOF. Вы не достигли EOF, потому что отметка EOF еще не была прочитана (говоря языком "binarically", ее концептуальное местоположение находится сразу после 30-й строки). Поэтому вы переходите к следующей итерации. x все еще составляет 30 от предыдущей итерации. Теперь Вы читаете из потока и получаете EOF. x остается 30, а ios::eofbit поднимается. Вы выводите в stderr x (который равен 30, как и в предыдущей итерации). Затем вы проверяете наличие EOF в состоянии цикла, и на этот раз вы выходите из цикла.

Попробовать это:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

Кстати, в вашем коде есть еще одна ошибка. Вы когда-нибудь пробовали запустить его на пустом файле? Поведение, которое вы получаете, происходит по той же самой причине.


  Сведения об ответе

PIRLO

22:26, 1st August, 2020

Мне нравится этот пример, который на данный момент оставляет чек, который вы могли бы добавить внутри блока while:

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

Не уверен, насколько это безопасно...


  Сведения об ответе

lourence

08:37, 25th August, 2020

Есть и альтернативный подход к этому:

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));


  Сведения об ответе

SEEYOU

12:46, 24th August, 2020

Без особых модификаций исходного кода он может стать :

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

но я предпочитаю два других решения выше в целом.


  Сведения об ответе

PAGE

01:31, 3rd August, 2020

Шаблон EOF нуждается в простом чтении для 'bootstrap' процесса проверки EOF. Учтите, что пустой файл изначально не будет иметь свой EOF набор до первого чтения. Простое чтение поймает EOF в этом случае и правильно пропустит цикл полностью.

Здесь вам нужно помнить, что вы не получите EOF до первой попытки прочитать доступные данные файла. Чтение точного количества данных не будет помечать EOF.

Я должен отметить, что если бы файл был пуст, ваш данный код был бы напечатан, так как EOF не позволит установить значение x при входе в цикл.

  • Ноль

Поэтому добавьте простое чтение и переместите чтение цикла в конец:

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}


  Сведения об ответе

KOMP

19:18, 22nd August, 2020

int x;
ifile >> x

while (!iFile.eof())
{  
    cerr << x << endl;        
    iFile >> x;      
}


  Сведения об ответе

dump

03:43, 2nd August, 2020

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться