2010-06-24 6 views
0

В моей программе я перенаправил stdout для печати в файл «console.txt». Функция записывает в этот файл, как это:посторонние пустые строки при чтении из ifstream

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 [email protected] 191 191 0 0 0 
str: 

str: 
str: Player [email protected] 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 [email protected] 191 191 0 0 0 
str: 

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

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

EDIT: Как предложил Amardeep, я сменил петлю while(!log.eof()) на петлю do{...}while(!log.fail);. Это фиксировало проблему бесконечного цикла, но не посторонние линии. Программа ведет себя, как и раньше, за исключением случаев, когда вошел в бесконечный цикл, теперь он не читает ничего, кроме пустых строк, где он должен прочитать вход, как это:

str: 

str: 

str: 

str: 
(etc.) 

ответ

1

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

+0

Я изменил 'while (! Log.eof())' на 'do {...} while (! Log.fail());' loop, и это исправило проблему бесконечного цикла, но он по-прежнему читается в посторонних пустых строках. – Max

+0

После прочтения вам нужно проверить «fail», но перед вызовом 'push'. Если вы не хотите иметь уродливую инструкцию if в середине цикла, вы можете сделать это, изменив свой код на 'log.getline (str, 256); while (! log.fail()) {cerr << "str:" << str << endl; stk.push (static_cast (str)); log.getline (str, 256) ;} ' – Brian

+0

Это почти исправило мою проблему. Теперь, я считаю, цикл чтения в порядке, теперь проблема связана с моей функцией clearLogFile. Если я прокомментирую это, все будет вести себя так, как я ожидал бы (хотя он читает старые данные, так как файл не очищается), при этом он все еще присутствует, перед каждой строкой реального ввода есть посторонние пустые строки и через некоторое время он перестает считывать входные данные вместе (видимо, проверка на 'fail' возвращает true с самого начала). – Max

1

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

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() возвращает ссылку на поток.

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

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

PS. Существует свободная функция, которая читает из потока в строку.

std::string line; 
std::getline(log, line); 
+0

Хорошо, спасибо. Это не совсем исправить мою проблему, но это сделало мой код лучше. С этого момента я буду помнить об этом. – Max

Смежные вопросы