Как записать данные консоли в текстовый файл на C ++? - PullRequest
0 голосов
/ 20 июля 2010

Я работаю над приложением для обмена файлами в C ++. Я хочу записать вывод консоли в отдельный файл, и в то же время я хочу также увидеть вывод в консоли. Кто-нибудь может мне помочь ... Заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 20 июля 2010

Вот и мы ...

#include <fstream>
    using std::ofstream;
#include <iostream>
    using std::cout;
    using std::endl;

int main( int argc, char* argv[] )
{
    ofstream file( "output.txt" ); // create output file stream to file output.txt
    if( !file ) // check stream for error (check if it opened the file correctly)
        cout << "error opening file for writing." << endl;

    for( int i=0; i<argc; ++i ) // argc contains the number of arguments
    {
        file << argv[i] << endl; // argv contains the char arrays of commandline arguments
        cout << argv[i] << endl;
    }
    file.close(); // always close a file stream when you're done with it.

    return 0;
}

PS: ОК, прочитайте ваш вопрос неправильно (консольный вывод / смешивание ввода), но я все еще понимаю идею, которую я думаю.

2 голосов
/ 20 июля 2010

Идея заключается в создании производного от std :: streambuf, который будет выводить данные как в файл, так и в cout. Затем создайте его экземпляр и используйте cout.rdbuf (...);

Вот код (протестирован с MSVC ++ 2010, должен работать на любом компиляторе):

class StreambufDoubler : public std::streambuf {
public:
    StreambufDoubler(std::streambuf* buf1, std::streambuf* buf2) :
            _buf1(buf1), _buf2(buf2), _buffer(128)
    {
        assert(_buf1 && _buf2);

        setg(0, 0, 0);
        setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
    }

    ~StreambufDoubler() {
        sync();
    }

    void imbue(const std::locale& loc) {
        _buf1->pubimbue(loc);
        _buf2->pubimbue(loc);
    }

    std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) {
        return seekoff(sp, std::ios_base::cur, which);
    }

    std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) {
        if (which | std::ios_base::in)
            throw(std::runtime_error("Can't use this class to read data"));

        // which one to return? good question
        // anyway seekpos and seekoff should never be called
        _buf1->pubseekoff(off, way, which);
        return _buf2->pubseekoff(off, way, which);
    }

    int overflow(int c) {
        int retValue = sync() ? EOF : 0;
        sputc(c);
        return retValue;
    }

    int sync() {
        _buf1->sputn(pbase(), pptr() - pbase());
        _buf2->sputn(pbase(), pptr() - pbase());
        setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
        return _buf1->pubsync() | _buf2->pubsync();
    }

private:
    std::streambuf*     _buf1;
    std::streambuf*     _buf2;

    std::vector<char>   _buffer;
};


int main() {
    std::ofstream myFile("file.txt");
    StreambufDoubler doubler(std::cout.rdbuf(), myFile.rdbuf());
    std::cout.rdbuf(&doubler);

    // your code here

    return 0;
}

Однако обратите внимание, что в лучшей реализации будут использоваться шаблоны, список потоковых буферов вместо двух и т. Д., Но я хотел, чтобы это было как можно проще.

1 голос
/ 20 июля 2010

На самом деле вы хотите, чтобы в режиме реального времени следовали строкам, добавляемым в журнал, который пишет ваше приложение.

В мире Unix есть простой инструмент с такой функцией, который называется tail.

Позвоните tail -f your_file, и вы увидите, что содержимое файла появляется в консоли практически в реальном времени.

К сожалению, tail не является стандартным инструментом в Windows (который, я полагаю, вы используете, в соответствии с тегами вашего вопроса). Однако его можно найти в пакете GnuWin32 , а также MSYS .

Есть также несколько нативных инструментов для Windows с той же функциональностью, я лично использую Tail For Win32 , который распространяется по лицензии GPL.

Итак, в заключение, я думаю, что ваша программа не должна выводить одни и те же данные в разные потоки, поскольку это может замедлить их без реальных преимуществ, в то время как существуют установленные инструменты, которые были разработаны специально для решения этой проблемы, без необходимости развивать что-либо.

0 голосов
/ 20 июля 2010

Я не программирую на c ++, но вот мой совет: создайте новый класс, который принимает InputStream (istream в c ++ или smth), и затем каждый входящий байт он передает в std.out и в файл.Я уверен, что есть способ изменить стандартный поток вывода с вышеупомянутым классом.Как я помню, std.out - это своего рода свойство cout.И снова, я провел неделю на C ++ более полугода назад, так что есть вероятность, что все, что я сказал, это мусор.

...