如何重新定义阻塞发球到原始阻塞和日志文件?

时间:2009-06-02 03:30:03

标签: c++ stream tee clog

我在这里看到了一个有用的开始:

http://www.cs.technion.ac.il/~imaman/programs/teestream.html

创建一个既阻塞又记录日志文件的新流,效果很好。

但是,如果我尝试将clog重新定义为新流,则它不起作用,因为新流与clog具有相同的rdbuf(),因此以下内容无效:

clog.rdbuf(myTee.rdbuf());

那么如何修改tee类以拥有自己的rdbuf()然后可以成为clog的目标呢?

感谢。

- 威廉

4 个答案:

答案 0 :(得分:3)

如果你真的想继续使用std :: clog而不是将输出发送到不同的流,你需要降低一级:不是从ostream派生,而是从streambuf派生。然后你可以这样做:

fstream logFile(...);
TeeBuf tbuf(logFile.rdbuf(), clog.rdbuf());
clog.rdbuf(&tbuf);

有关如何派生自己的streambuf课程的更多信息,请参阅here

答案 1 :(得分:2)

你不想做你想做的事,因为'tee'不能在rdbuf级别工作。因此,将rdbuf设置为其他内容将不起作用,输出将仅转到一个流。

你需要按照那里的例子:

e.g。

fstream clog_file(...);
xstream clog_x(...);
TeeStream clog(clog_file, clog_x);

然后在任何地方使用阻塞而不是原来的阻塞。

答案 2 :(得分:1)

这是我创建的课程似乎完成了这项工作,感谢所有帮助过的人!

- 威廉

class TeeStream : public std::basic_filebuf<char, std::char_traits<char> >
{
private:
  class FileStream : public std::ofstream {
  public:
    FileStream()
      : logFileName("/my/log/file/location.log") {
      open(logFileName.c_str(), ios::out | ios::trunc);

      if (fail()) {
        cerr << "Error: failed to open log file: " << logFileName << endl;
        exit(1);
      }
    }
    ~FileStream() {
      close();
    }

    const char *getLogFileName() const {
      return logFileName.c_str();
    }

  private:
    const string logFileName;

  };

public:
  typedef std::char_traits<char> traits;
  typedef std::basic_filebuf<char, traits> baseClass;

  TeeStream()
    :  baseClass(),
       _logOutputStream(),
       _clogBuf(clog.rdbuf()),
       _fileBuf(_logOutputStream.rdbuf()) {
    clog.rdbuf(this);
    _logOutputStream << "Log file starts here:" << endl;
  }
  ~TeeStream() {
    clog.rdbuf(_clogBuf);
  }

  int_type overflow(char_type additionalChar =traits::eof()) {
    const int_type eof = traits::eof();
    const char_type additionalCharacter = traits::to_char_type(additionalChar);
    const int_type result1 = _clogBuf->sputc(additionalCharacter);
    const int_type result2 = _fileBuf->sputc(additionalCharacter);

    if (traits::eq_int_type(eof, result1)) {
      return eof;
    } else {
      return result2;
    }
  }

  int sync() {
    const int result1 = _clogBuf->pubsync();
    const int result2 = _fileBuf->pubsync();

    if (result1 == -1) {
      return -1;
    } else {
      return result2;
    }
  }

private:
  FileStream _logOutputStream;
  streambuf * const _clogBuf;
  streambuf * const _fileBuf;

};

答案 3 :(得分:1)

我只会使用Boost iostreams来做它。

#include <iostream>
#include <fstream>
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>

#include <iostream>

#include <fstream>