【C++进阶】C++创建文件/屏幕输出流类(将信息同时输出到文件和屏幕)

445 阅读1分钟

在软件的调试技术中,很重要的一个技术是将软件运行过程中的一些信息写入到“日志文件”中。但是同时还要将信息显示到屏幕上,以方便程序员实时查看这些信息。
最简单的一种办法是这样的:

std::ofstream output("debug.log", ios::out);
output << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;
cout << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;

不过,上面的代码看起来很愚蠢。
下面使用streambuf构造一个自己的类,来实现这个功能

#include <streambuf>
#include <iostream>
#include <fstream>

//Linux tee命令用于读取标准输入的数据,并将其内容输出成文件。
//tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
class teebuf : public std::streambuf
{
public:
    // Construct a streambuf which tees output to both input
    // streambufs.
    teebuf(std::streambuf* sb1, std::streambuf* sb2)
        : sb1(sb1)
        , sb2(sb2)
    {
    }
private:
    // This tee buffer has no buffer. So every character "overflows"
    // and can be put directly into the teed buffers.
    virtual int overflow(int c)
    {
        if (c == EOF)
        {
            return !EOF;
        }
        else
        {
            int const r1 = sb1->sputc(c);
            int const r2 = sb2->sputc(c);
            return r1 == EOF || r2 == EOF ? EOF : c;
        }
    }

    // Sync both teed buffers.
    virtual int sync()
    {
        int const r1 = sb1->pubsync();
        int const r2 = sb2->pubsync();
        return r1 == 0 && r2 == 0 ? 0 : -1;
    }
private:
    std::streambuf* sb1;
    std::streambuf* sb2;
};

class teestream : public std::ostream
{
public:
    // Construct an ostream which tees output to the supplied
    // ostreams.
    teestream(std::ostream& o1, std::ostream& o2);
private:
    teebuf tbuf;
};

teestream::teestream(std::ostream& o1, std::ostream& o2)
    : std::ostream(&tbuf)
    , tbuf(o1.rdbuf(), o2.rdbuf())
{
}

int main()
{
    std::ofstream output("debug.log");
    //1、创建文件/屏幕输出流对象tee
    teestream tee(std::cout, output);

    auto x = 1.1;
    tee << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;

    return 0;
}

效果:
在这里插入图片描述