Using freopen() to print to file and screen

柔情痞子 提交于 2019-11-29 13:15:45

I don't know a simple way to achieve that, but I've managed to solve this somehow.

Using fstreams you can output to file the same way you can write to console.

#include <fstream>

int main()
{
     std::ofstream f("file.txt");
     f << "something";
}

Now there's a point we can start: is there a way we can output to the console and file simultaneously?

I've recently written stream demultiplexer to address that problem:

#include <vector>
#include <ostream>
class stream_demultiplexer
{
private:
    typedef std::vector<std::ostream*> str_cont;
    str_cont d;
public:
    stream_demultiplexer& put(std::ostream::char_type ch)
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (*it)->put(ch);
        return *this;
    }

    stream_demultiplexer& write(const std::ostream::char_type* s, std::streamsize count)
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (*it)->write(s, count);
        return *this;
    }

    stream_demultiplexer& flush()
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (*it)->flush();
        return *this;
    }


    template<typename T>
    stream_demultiplexer& operator<<( const T& obj )
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (**it) << obj;
        return *this;
    }

    stream_demultiplexer& operator<<(std::ios_base& (*func)(std::ios_base&))
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (**it) << func;
        return *this;
    }

    template<typename CharT, typename Traits>
    stream_demultiplexer& operator<<(std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) )
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (**it) << func;
        return *this;
    }

    stream_demultiplexer& operator<<(std::ostream& (*func)(std::ostream&) )
    {
        for(str_cont::iterator it = d.begin(); it != d.end(); ++it)
            (**it) << func;
        return *this;
    }

    void add_stream(std::ostream& ss)
    {
        d.push_back(&ss);
    }
};

You can use it like this:

stream_demultiplexer spl;
std::ofstream f("file.txt");
spl.add_stream(f);
spl.add_stream(std::cout);
spl << 55 << " HELLO WORLD";

My approach has advantage that manipulators and unformatted output works correctly:

spl << 76 << " " << std::hex << 76 << std::endl;
spl.put('a');
spl.write("ABCDE", 5);

The easy way in a UNIX-like environment is to use the shell command tee:

$ my-program | tee output.txt

will copy stdout to the terminal, and also to the file output.txt.


If you have to do it in code, you could use your own output stream instead of cout, which forwards every operator<< to two (or more) ostreams. This feels nicer (to me) than mucking around with the C output file underlying the C++ ostream cout.

#include <ostream>

class Tee {
    std::ostream &first, &second;

    template<typename T> friend Tee& operator<< (Tee&, T);

public:
    Tee(std::ostream &f, std::ostream &s) : first(f), second(s) {}
};

template <typename T>
Tee& operator<< (Tee &t, T val)
{
    t.first << val;
    t.second << val;
    return t;
}

Then, if you replace your freopen line with:

std::ofstream outfile("file.txt");
Tee tee(std::cout, outfile);

you can just use tee << instead of cout <<.

Note that you'll either need to pass tee into your functions, or make it a global for that to work.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!