Почему eof() никогда не возвращает true?

Я пытаюсь заставить свою программу читать данные из файла данных (.dat) (который на самом деле является просто текстовым файлом). Поэтому, конечно, я использую условие цикла while(!file.eof()), но оно никогда не возвращает true. Вот моя функция:

void Table::readIn(const char finput[]){
    std::ifstream file;

    file.open(finput);

    if (!file.is_open())
    {
        std::cout << "Cannot open " << finput << std::endl;
        return;
    }
    char key[100];
    file.get(key, 99, '\n');
    while (!file.eof())
    {
        stock * item = new stock;
        item->setTick(key);
        file.get(key, 99, '\n');
        item->setName(key);
        file.get(key, 99, '\n');
        item->setValue(atof(key));
        file.get(key, 99, '\n');
        item->setDate(key);
        file.get(key, 99, '\n');
        item->setYearReturn(atof(key));
        file.get(key, 99, '\n');
        addStock(item);
    }
}

и вот что в моем файле данных:

TSLA
Tesla Motors, Inc.
30160000000
November 6, 2015
13.1

Я хотел бы дать вам больше информации, ребята, но тот факт, что программа бесконечно повторяет цикл while (!file.eof()), - это все, что я знаю об этой проблеме.

Изменить: я прогнал это через отладчик с точкой останова в каждой строке цикла while. Я обнаружил, что первый вызов get() (перед циклом while) устанавливает key в правильное значение, но каждый последующий вызов get() устанавливает key в "". Я предполагаю, что это связано с тем, что программа никогда не читает первый символ '\n' в файле. Ребята, вы знаете, как это исправить?

Редактировать 2: этот вопрос отличается от: Почему iostream::eof внутри условия цикла считается неправильным? потому что я должен читать в более одной строки каждый раз, когда я прохожу цикл while.


person Logan Kling    schedule 07.11.2015    source источник
comment
Начнем с того, что флаги eofbit не устанавливаются до тех пор, пока вы не попытаетесь прочитать из-за конца файла, что означает, что ваш цикл не будет работать так, как вы ожидаете. Чтобы продолжить, попробуйте выполнить код построчно в отладчике, ваше чтение тоже не сработает так, как вы ожидаете.   -  person Some programmer dude    schedule 07.11.2015
comment
@JoachimPileborg Хорошо, первый вызов get() (перед циклом while) устанавливает key правильное значение, но каждый вызов get() после этого устанавливает key в . Я предполагаю, что это связано с тем, что программа никогда не читает первый символ '\n' в файле. Знаете, как я это исправлю?   -  person Logan Kling    schedule 07.11.2015
comment
Самое простое решение? Используйте std::string и std::getline для чтения строк.   -  person Some programmer dude    schedule 07.11.2015
comment
Поэтому, конечно, я использую условие цикла while(!file.eof()) — что неверно…   -  person The Paramagnetic Croissant    schedule 07.11.2015
comment
@LarryK - После того, как вы решили проблему file.get(), проблема while (!file.eof()) по-прежнему неверна (даже если это не то, о чем вы спрашивали).   -  person Bo Persson    schedule 07.11.2015


Ответы (2)


Проблема с использованием вами std::istream::get заключается в том, что он не потребляет разделитель. Это будет нормально работать для первого вызова, но затем следующий вызов сразу увидит новую строку, оставшуюся от предыдущего вызова, и ничего не прочитает.

Если вы хотите читать строки, используйте либо std::istream::getline (если вы настаиваете на с использованием массивов символов) или std::getline с std::string, что я и рекомендую.


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

if (!std::getline(...))
    // end of file or error
person Some programmer dude    schedule 07.11.2015
comment
Я получаю Error: getline() is undefined - person Logan Kling; 07.11.2015
comment
Предполагая код, который у меня был до редактирования 3, я смог исправить это, заменив каждый из моих вызовов file.get() вызовами file.getline. Вы должны обновить свой ответ, чтобы указать это (поскольку getline() отбрасывает разделитель из входного потока, а get() нет). - person Logan Kling; 07.11.2015
comment
@LarryK: std::getline в <string>. Вы должны включить этот заголовок, чтобы использовать его. - person Christian Hackl; 07.11.2015
comment
@LarryK И также передайте правильные аргументы std::getline. - person Some programmer dude; 07.11.2015
comment
@ChristianHackl Я использовал std::istream::getline, а не std::getline. - person Logan Kling; 08.11.2015
comment
@LarryK: Тогда в этом проблема. Используйте 1_. - person Christian Hackl; 08.11.2015
comment
@ChristianHackl Использование std::istream::getline вместо std::istream::get решило мою проблему. - person Logan Kling; 09.11.2015

Вам придется заменить эту строку while (!file.eof()) на

while (true)
    {
        /*code*/
        file.get(key, 99, '\n');
        if (file.eof()) { break; } // and similarly for other usages where you are reading the stream
        /*code*/
    }

Редактировать: Хорошо. Похоже, ваша проблема кроется здесь, цитируя документацию ifstream::get :

следующий доступный входной символ c равен delim, как определено функцией Traits::eq(c, delim). Этот символ не извлекается

Таким образом, после каждого вызова get ваш указатель поиска по-прежнему указывает на разделитель. Таким образом, после первого вызова get продолжает сталкиваться с символом новой строки и, следовательно, возвращает вам пустые данные. Вы можете либо добавить фиктивное чтение для использования этого разделителя, либо, что еще лучше, использовать getline

person bashrc    schedule 07.11.2015
comment
Это не решило проблему. - person Logan Kling; 07.11.2015
comment
@LarryK, можете ли вы обновить код тем, что вы изменили. - person bashrc; 07.11.2015
comment
Почему вы ожидаете, что это сработает лучше, чем то, что у него есть? Файл не перейдет из состояния eof в состояние не-eof, если он не очистит флаг ошибки. - person Benjamin Lindley; 07.11.2015