2012-03-19 33 views
4

C++では、stdoutの出力をコンソールとファイルの両方にミラーリングするスマートな方法はありますか? this questionのようにする方法があることを願っています。コンソール出力をC++のファイルに出力

編集:ちょうど標準ライブラリ(すなわち:なしブースト)でこれを行うことができるようにいいだろう。..

+1

私は、あなたが一番近いのは、賢明に書かれた '#define'か2つだと思います。 – suszterpatt

答えて

1

あなたはBoost.Iostreamsによって提供さTee Deviceを試みることができます。

A Teeデバイスは、出力を複数のストリームに出力します。私が知る限り、writeコールから理論的には無限の出力デバイスに達するようにそれらを連鎖させることができます。

This answerは、あなたが望むものを正確に行う方法の例を示しています。

3

また、プログラムを起動してteeコマンドにパイプするだけです。

1

std::streambufを拡張し、std::ofstreamのメンバーを持つクラスを作成すると、これを行うことができます。 std::streambuf::overflowstd::streambuf::syncのメンバー関数をオーバーライドすると、すべて設定されます。

以下のコードの大部分はhereです。ファイルミラーリングのために私が追加したもの( "ADDED:")が指摘されています。これは私が仕事をしているときに過度に複雑になる可能性があり、単純化するためにそれを完全に覆すことはできませんが、このようにすることのボーナス(std::streambuf*を使用する代わりに、 。std::coutへの書き込み、外部ライブラリは)

#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; 
} 

希望はこのことができます

mystreambuf.hファイルに書き込みます。歓声

関連する問題