I am trying to use freopen() to print to a text file and the screen, but I am only achieving the printing to a file.
I was wondering if there was an easy to save the
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.
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);