C++では、stdoutの出力をコンソールとファイルの両方にミラーリングするスマートな方法はありますか? this questionのようにする方法があることを願っています。コンソール出力をC++のファイルに出力
編集:ちょうど標準ライブラリ(すなわち:なしブースト)でこれを行うことができるようにいいだろう。..
C++では、stdoutの出力をコンソールとファイルの両方にミラーリングするスマートな方法はありますか? this questionのようにする方法があることを願っています。コンソール出力をC++のファイルに出力
編集:ちょうど標準ライブラリ(すなわち:なしブースト)でこれを行うことができるようにいいだろう。..
あなたはBoost.Iostreamsによって提供さTee Deviceを試みることができます。
A Teeデバイスは、出力を複数のストリームに出力します。私が知る限り、write
コールから理論的には無限の出力デバイスに達するようにそれらを連鎖させることができます。
This answerは、あなたが望むものを正確に行う方法の例を示しています。
また、プログラムを起動してteeコマンドにパイプするだけです。
std::streambuf
を拡張し、std::ofstream
のメンバーを持つクラスを作成すると、これを行うことができます。 std::streambuf::overflow
とstd::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ファイルに書き込みます。歓声
私は、あなたが一番近いのは、賢明に書かれた '#define'か2つだと思います。 – suszterpatt