4

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

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

并且它非常适合制作一个同时进入 clog 和日志文件的新流。

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

clog.rdbuf(myTee.rdbuf());

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

谢谢。

-威廉

4

4 回答 4

3

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

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

有关如何派生您自己的 streambuf 类的更多信息,请参见此处

于 2009-06-03T02:00:28.483 回答
2

您不想做您想做的事情,因为“tee”不在 rdbuf 级别上工作。因此将 rdbuf 设置为其他内容将不起作用,输出只会转到一个流。

你需要按照那里的例子:

例如

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

然后到处使用木屐代替原来的木屐。

于 2009-06-02T06:59:57.540 回答
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;

};
于 2009-06-04T03:54:49.010 回答
1

我只会使用 Boost iostreams 的东西来做到这一点。

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

int main(const int a_argc, const char *a_args[])
{
    namespace io = boost::iostreams;
    typedef io::tee_device<std::ofstream, std::ostream> TeeDevice;
    typedef io::stream<TeeDevice> TeeStream;

    std::ofstream flog("logFile.txt");
    //We need to copy clog, otherwise we get infinite recursion
    //later on when we reassign clog's rdbuf.
    std::ostream clogCopy(std::clog.rdbuf());

    TeeDevice logTee(flog, clogCopy);
    TeeStream logTeeStream(logTee);

    logTeeStream << "This text gets clogged and flogged." << std::endl;

    //Modify clog to automatically go through the tee.
    std::streambuf *originalRdBuf = std::clog.rdbuf(logTeeStream.rdbuf());  

    std::clog << "This text doesn't only get clogged, it's flogged too." << std::endl;

    std::clog.rdbuf(originalRdBuf);
    std::clog << "This text avoids flogging." << std::endl;
}

于 2009-06-14T10:27:11.707 回答