посторонние пустые строки при чтении из ifstream - PullRequest
0 голосов
/ 24 июня 2010

В моей программе я перенаправил стандартный вывод для печати в файл 'console.txt'.Функция пишет в этот файл так:

void printToConsole(const std::string& text, const TCODColor& fc, const TCODColor& bc)
    {
        // write the string
        cout << text << "@";

        // write the two color values
        cout << static_cast<int>(fc.r) << " "
             << static_cast<int>(fc.g) << " " 
             << static_cast<int>(fc.b) << " "
             << static_cast<int>(bc.r) << " "
             << static_cast<int>(bc.g) << " " 
             << static_cast<int>(bc.b) << " " << endl;
    }

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

   void Console::readLogFile()
   {
        ifstream log("console.txt", ifstream::in);
        if(!log.is_open())
        {
            cerr << "ERROR: console.txt not found!" << endl;
            return;
        }

        // read new input into the stack
        char str[256];
        while(!log.eof())
        {
            log.getline(str, 256);
            cerr << "str: " << str << endl;
            stk.push(static_cast<string>(str));
            // stk is a std::stack<std::string> member of the class this function
            // belongs to.
        }
        cerr << endl;

        /* Do some stuff with str and stk here */

        log.close();
        clearLogFile();
    }

    void Console::clearLogFile()
    {
        FILE* log;
        log = fopen("console.txt", "w");
        fclose(log);
    }

Часто console.txt пуст, когда readLogFile называется.Я ожидаю, что цикл while(!log.eof()) никогда не будет выполняться в этом случае, но он выполняется.В файле всегда есть хотя бы одна посторонняя пустая строка, иногда две, и когда входные данные считываются из файла, строка ввода помещается между двумя пустыми строками.После нескольких вызовов этой функции цикл while(!log.eof()) переходит в бесконечный цикл, вытаскивая пустые строки из файла.Типичный прогон программы выглядит следующим образом:

str: 

str: Player moved.@191 191 191 0 0 0
str: 

str: 
str: Player moved.@191 191 191 0 0 0 
str: 

str: // there should be a 'Player moved.' line in here
str:

str: // here as well
str:

str: // also here
str:

str: 
str: Player moved.@191 191 191 0 0 0 
str: 

str:
str:
str:
str:
str:
str:
(onto infinite loop)

Кто-нибудь может увидеть, что я здесь делаю неправильно?

РЕДАКТИРОВАТЬ: Как предложил Амардип, я изменил цикл while(!log.eof()) наdo{...}while(!log.fail); петля.Это решило проблему бесконечного цикла, но не посторонние линии.Программа ведет себя так же, как и раньше, за исключением того, что когда-то она вошла в бесконечный цикл, теперь она читает только пустые строки, где она должна читать ввод, например:

str:

str:

str:

str: 
(etc.)

Ответы [ 2 ]

1 голос
/ 25 июня 2010

Стандартный анти-паттер для чтения файла.

    while(!log.eof())
    {
        log.getline(str, 256);
        cerr << "str: " << str << endl;
        stk.push(static_cast<string>(str));
        // stk is a std::stack<std::string> member of the class this function
        // belongs to.
    }

попробуйте это:

    while(log.getline(str, 256))
    {
        cerr << "str: " << str << endl;
        stk.push(string(str));
    }

Это работает, потому что метод getline () возвращает ссылку на поток.

Когда поток используется в логическом контексте, он преобразуется в логическое значение (на самом деле не для педантиков, а для начинающих).Если после чтения поток все еще находится в хорошем состоянии (т. Е. Сработало чтение), он преобразуется в true.Если поток находится в плохом состоянии (т. Е. Сбой чтения), он преобразуется в false.Поэтому, если чтение сработало, вводится цикл.Если чтение не удалось (потому что, возможно, EOL читается), то цикл не вводится.

Обратите внимание, что ваша версия не удалась, потому что вы не тестировали eof () после чтения (getline ()).Это потому, что при последнем прочтении все символы читаются до EOF.Но это означает, что флаг eof не установлен.Только когда вы попытаетесь действительно прочитать за пределами EOF (это происходит, только если вы читаете что-то после того, как последнее чтение прочитало все остальные символы), флаг EOF устанавливается.

PS.Есть бесплатная функция, которая читает из потока в строку.

std::string line;
std::getline(log, line);
1 голос
/ 24 июня 2010

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

...