Зеркальное отображение вывода консоли в файл на c ++ - PullRequest
5 голосов
/ 19 марта 2012

В C ++ есть ли умный способ отразить вывод из stdout как на консоль, так и в файл?Я надеюсь, что есть способ сделать это, как в этот вопрос .

Редактировать: Было бы неплохо сделать это с помощью только стандартных библиотек (т.е. без повышения) ..

Ответы [ 3 ]

3 голосов
/ 19 марта 2012

Либо просто запустите программу, чтобы она передавалась по команде tee .

1 голос
/ 19 марта 2012

Вы можете сделать это, создав класс, который расширяет std::streambuf и имеет член std::ofstream. После переопределения функций-членов std::streambuf::overflow и std::streambuf::sync все будет готово.

Большая часть кода ниже взята из здесь . Материал, который я добавил ("ADDED:") для зеркалирования файлов, указан. Это может быть слишком сложно, так как я на работе и не могу полностью проанализировать его, чтобы упростить его, но это работает - бонус в том, чтобы делать это таким образом (вместо использования std::streambuf* в том, что любой код (скажем, вы иметь внешнюю библиотеку), которая пишет в std::cout, пишет в ваш файл.

mystreambuf.h

#ifndef MYSTREAMBUF_H
#define MYSTREAMBUF_H

template <typename charT, typename traits = std::char_traits<charT> >
class mystreambuf : public std::basic_streambuf<charT, traits>
{
public:
    // The size of the input and output buffers.
    static const size_t BUFF_SIZE = 1024;
    typedef traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    // You can use any method that you want, but here, we'll just take in a raw streambuf as a
    // slave I/O object.  xor_char is what each character is xored with before output.
    explicit mystreambuf(std::streambuf* buf)
        : out_buf_(new charT[BUFF_SIZE])
    {
        // ADDED: store the original cout stream and open our output file
        this->original_cout = buf;
        outfile.open("test.txt");

        // Initialize the put pointer.  Overflow won't get called until this buffer is filled up,
        // so we need to use valid pointers.
        this->setp(out_buf_, out_buf_ + BUFF_SIZE - 1);
    }

    // It's a good idea to release any resources when done using them.
    ~mystreambuf() {
        delete [] out_buf_;
        // ADDED: restore cout, close file
        std::cout.rdbuf(original_cout);
        outfile.flush();
        outfile.close();
    }

protected:
    // This is called when there are too many characters in the buffer (thus, a write needs to be performed).
    virtual int_type overflow(int_type c);
    // This is called when the buffer needs to be flushed.
    virtual int_type sync();


private:
    // Output buffer
    charT* out_buf_;
    // ADDED: tracking the original std::cout stream & the file stream to open
    std::streambuf* original_cout;
    std::ofstream outfile;
};

#endif

mystreambuf.cpp

// Based on class by perfectly.insane from http://www.dreamincode.net/code/snippet2499.htm

#include <fstream>
#include <iostream>
#include <streambuf>

#include "mystreambuf.h"

// This function is called when the output buffer is filled.
// In this function, the buffer should be written to wherever it should
// be written to (in this case, the streambuf object that this is controlling).
template <typename charT, typename traits>
typename mystreambuf<charT, traits>::int_type
mystreambuf<charT, traits>::overflow(typename mystreambuf<charT, traits>::int_type c)
{
    charT* ibegin = this->out_buf_;
    charT* iend = this->pptr();

    // Reset the put pointers to indicate that the buffer is free
    // (at least it will be at the end of this function).
    setp(out_buf_, out_buf_ + BUFF_SIZE + 1);

    // If this is the end, add an eof character to the buffer.
    // This is why the pointers passed to setp are off by 1
    // (to reserve room for this).
    if(!traits_type::eq_int_type(c, traits_type::eof())) {
        *iend++ = traits_type::to_char_type(c);
    }

    // Compute the write length.
    int_type ilen = iend - ibegin;

    // ADDED: restore cout to its original stream, output to it, output to the file, then set cout's stream back to this, our streambuf)
    std::cout.rdbuf(original_cout);
    out_buf_[ilen] = '\0';
    std::cout << out_buf_;
    outfile << out_buf_;
    std::cout.rdbuf(this);

    return traits_type::not_eof(c);
}

// This is called to flush the buffer.
// This is called when we're done with the file stream (or when .flush() is called).
template <typename charT, typename traits>
typename mystreambuf<charT, traits>::int_type
mystreambuf<charT, traits>::sync()
{
    return traits_type::eq_int_type(this->overflow(traits_type::eof()),
                                    traits_type::eof()) ? -1 : 0;
}


int main(int argc, char* argv[]) {
    mystreambuf<char> filter(std::cout.rdbuf());
    std::cout.rdbuf( &filter );
    std::cout << "Hello World" << std::endl;

    return 0;
}

надеюсь, это поможет; ура

1 голос
/ 19 марта 2012

Вы можете попробовать устройство Tee , предоставленное Boost.Iostreams.

Устройство Tee направляет вывод в несколько потоков.Насколько я знаю, вы можете объединить их в цепочку для достижения теоретически бесконечных выходных устройств с одного write вызова.

Этот ответ показывает пример того, как делать именно то, что вы хотите.

...