Файловые потоки ввода-вывода C++: запись из одного файла в другой с использованием оператора‹‹ и rdbuf()

У меня вопрос о копировании данных из одного файла в другой на C++ (fstream) с помощью оператора‹‹. Вот фрагмент кода, который работает для меня:

    #include <fstream>
    #include <string>

    void writeTo(string &fname, ofstream &out){
        ifstream in;
        in.open(fname.c_str(),fstream::binary);
        if(in.good()){
            out<<in.rdbuf();
            in.close();
        }else{
            //error
        }
    }

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


person John    schedule 24.05.2011    source источник
comment
eof устанавливается, когда вы пытаетесь прочитать за концом ввода, а не когда вы его достигаете.   -  person Lightness Races in Orbit    schedule 24.05.2011
comment
Попробуйте, может быть, только из ‹‹ в;. Возможно, работа напрямую с rdbuf() не влияет на флаги in.   -  person selalerer    schedule 24.05.2011


Ответы (3)


EOF-бит устанавливается при попытке прочитать символ, но он недоступен (т.е. вы уже израсходовали все в строке). По-видимому, std::ostream::operator<<() не пытается читать дальше конца строки, поэтому бит никогда не устанавливается.

Вы сможете обойти это, попытавшись получить доступ к следующему символу: добавьте in.peek() перед тем, как отметите in.eof(). Я протестировал это исправление, и оно работает.

person Michael Koval    schedule 24.05.2011
comment
Я хотел бы знать, почему это неправильно, тем более что предложенное мной исправление работает. Широко задокументировано, что бит EOF не устанавливается при чтении последнего символа в файле: только когда вы пытаетесь прочитать за конец файла. - person Michael Koval; 24.05.2011
comment
Я имел в виду operator<<, так как он используется для чтения из in: out << in.rdbuf(). Поскольку чтение из in.rdbuf() оставляет in пустым и не устанавливает бит EOF, попытка чтения одного символа (например, с in.peek()) установит бит EOF [при попытке чтения после конца потока]. - person Michael Koval; 24.05.2011
comment
Хорошо, я удалил все свои комментарии, так как совершенно не понял, что вы сказали. Извинения. - person ; 24.05.2011
comment
Без проблем. Спасибо за обсуждение. - person Michael Koval; 25.05.2011

Причина, по которой ни один из битов состояния не установлен во входном файле, заключается в том, что вы читаете streambuf, а не istream; фактическое чтение происходит в ostream::operator<<, который не имеет доступа к istream.

Однако я не уверен, что это имеет значение. Ввод будет считываться до тех пор, пока streambuf::sgetc не вернет EOF. Что привело бы к установке eofbit в istream, если вы читали через istream. Единственное, что могло бы предотвратить это, если бы вы читали istream, это если бы streambuf::sgetc выдало исключение, которое привело бы к установке badbit в istream; не существует другого механизма, позволяющего вводу streambuf сообщать об ошибке чтения. Поэтому заверните out << in.rdbuf() в блок try ... catch и надейтесь, что реализация действительно проверит аппаратные ошибки. (Я недавно не проверял, но многие ранние реализации полностью игнорировали ошибки чтения, рассматривая их как обычный конец файла.)

И, конечно же, поскольку вы буквально читаете байты (несмотря на <<, я не понимаю, как можно назвать этот форматированный ввод), вам не нужно учитывать третий возможный источник ошибок, ошибку формата (например, "abc" при вводе int).

person James Kanze    schedule 24.05.2011

Попробуйте in.rdbuf()->sgetc() == EOF.

Ссылка: http://www.cplusplus.com/reference/iostream/streambuf/sgetc/

person Robᵩ    schedule 24.05.2011