【问题标题】:Mirror console output to file in c++将控制台输出镜像到 C++ 中的文件
【发布时间】:2012-03-19 02:37:22
【问题描述】:

在 C++ 中,有没有一种聪明的方法可以将 stdout 的输出镜像到控制台和文件? 我希望有一种方法可以像this question 那样做。

编辑:如果能够仅使用标准库来做到这一点会很好(即:没有提升)..

【问题讨论】:

  • 我认为你能找到的最接近的是写得很巧妙的#define或两个。

标签: c++ io stdout


【解决方案1】:

或者,只需启动您的程序,将其通过管道传送到tee 命令。

【讨论】:

    【解决方案2】:

    你可以试试 Boost.Iostreams 提供的Tee Device

    Tee 设备将输出定向到多个流。据我所知,您可以通过一次write 调用将它们链接起来以达到理论上无限的输出设备。

    This answer 展示了一个示例,说明如何完全按照您的意愿行事。

    【讨论】:

      【解决方案3】:

      您可以通过创建一个扩展std::streambuf 并具有std::ofstream 成员的类来做到这一点。覆盖std::streambuf::overflowstd::streambuf::sync 成员函数后,一切就绪。

      下面的大部分代码来自here。指出了我为文件镜像添加的内容(“添加:”)。这可能过于复杂,因为我正在工作并且无法完全研究它以简化它,但它确实有效 - 这样做的好处(而不是仅仅使用 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;
      }
      

      希望这会有所帮助;干杯

      【讨论】:

        猜你喜欢
        • 2010-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多