Используйте getline () без установки failbit - PullRequest
7 голосов
/ 22 октября 2011

Можно ли использовать getline() для чтения допустимого файла без установки failbit?Я хотел бы использовать failbit, чтобы генерировалось исключение, если входной файл не читается.

Следующий код всегда выводит basic_ios::clear в качестве последней строки - даже если указан допустимый ввод.

test.cc:

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

int main(int argc, char* argv[])
{
    ifstream inf;
    string line;

    inf.exceptions(ifstream::failbit);
    try {
        inf.open(argv[1]);
        while(getline(inf,line))
            cout << line << endl;
        inf.close();
    } catch(ifstream::failure e) {
        cout << e.what() << endl;
    }
}

input.txt:

the first line
the second line
the last line

Результаты:

$ ./a.out input.txt 
the first line
the second line
the last line
basic_ios::clear

1 Ответ

8 голосов
/ 22 октября 2011

Вы не можете.Стандарт гласит: getline:

Если функция не извлекает никаких символов, она вызывает is.setstate(ios_base::failbit), что может вызвать ios_base::failure (27.5.5.4).

Если ваш файл заканчивается пустой строкой, то есть последний символ '\ n', то последний вызов getline не читает символов и завершается неудачно.В самом деле, как вы хотели, чтобы цикл завершился, если бы он не устанавливал failbit?Условие while всегда будет истинным, и оно будет работать вечно.

Я думаю, что вы неправильно понимаете, что означает failbit. не означает, что файл не может быть прочитан.Это скорее используется как флаг, что последняя операция прошла успешно.Для обозначения сбоя низкого уровня используется бадбит, но он мало пригоден для стандартных файловых потоков.failbit и eofbit обычно не следует интерпретировать как исключительные ситуации.С другой стороны, следует использовать badbit, и я бы сказал, что fstream :: open должен был установить badbit вместо failbit.

В любом случае приведенный выше код должен быть записан как:

try {
    ifstream inf(argv[1]);
    if(!inf) throw SomeError("Cannot open file", argv[1]);
    string line;
    while(getline(inf,line))
        cout << line << endl;
    inf.close();
} catch(const std::exception& e) {
    cout << e.what() << endl;
}
...