I want to be notified when a file associated with a std::istream is read from using the istream and the same with an ostream being written to. With this in mind I decided to try deriving my own std::basic_filebuf, and just to experiment I tried to override the xsgetn() and xsputn() functions so that they would output to the console before calling the parent implementation:
#include <iostream>
#include <fstream>
#include <cstdio>
class MyFileBuff : public std::filebuf
{
public:
std::streamsize xsgetn(char_type* s, std::streamsize count) override
{
std::cout << "using my xsgetn()" << std::endl;
return std::filebuf::xsgetn(s, count);
}
std::streamsize xsputn(const char_type* s, std::streamsize count) override
{
std::cout << "using my xsputn()" << std::endl;
return std::filebuf::xsputn(s, count);
}
using std::filebuf::basic_filebuf;
};
int main()
{
//open file
FILE* filePtr{ nullptr };
fopen_s(&filePtr, "text.txt", "w+");
//associate file with instance of custom std:filebuff
MyFileBuff fileBuff(filePtr);
//initalize i/o streams with file buffer
std::istream myIStream(&fileBuff);
std::ostream myOStream(&fileBuff);
//output to file
myOStream << "hello world" << std::endl;
const short buffSize{ 1024 };
char buff[buffSize];
myIStream.seekg(0);
//read from file
myIStream.getline(buff, buffSize);
//output what was read to console
std::cout << buff << std::endl;
return 0;
}
This outputs:
> using my xsputn()
> hello world
As you can see, my override of xsputn() is called on the write operation. But despite the read operation completing successfully, my override of xsgetn() is never called. I would like help understanding why.
I have also tried overloading the std::basic_filebuf::uflow() and std::basic_filebuf::underflow() functions in a similar manner and they do successfully output to the console when the istream is read, but I don't understand why xsgetn() never gets called?
I try to find a way to catch the standard outputs in a C++ application. This app is quite large, using third parties and may use outputs in both C or C++ ways (assuming there are std::cout calls as well as printf calls)
we can simulate by something like:
void MyAwesomeApp()
{
std::cout << "I am starting" << std::endl;
std::cerr << "Getting a warning!\n";
printf("With old style print\n");
std::cout << "That's all folk!\n";
}
I already tried 2 approachs:
1. std::streambuf
class MyStreambuf : public std::streambuf {
public:
explicit MyStreambuf(const std::string& fileName = "" )
{
if (!fileName.empty())
{
_file1.open(std::filesystem::temp_directory_path() / fileName,std::ios::out);
_file2.open(std::filesystem::current_path() / fileName, std::ios::out);
}
if (_file1.is_open())
{
saveOut = std::cout.rdbuf();
std::cout.rdbuf(this);
saveErr = std::cerr.rdbuf();
std::cerr.rdbuf(this);
}
}
const std::string& GetOutput()const{return saveStr;}
~MyStreambuf() override
{
if (saveOut) std::cout.rdbuf(saveOut);
if (saveErr) std::cerr.rdbuf(saveErr);
_file1.close();
_file2.close();
}
protected:
std::streamsize xsputn(char_type const* s, std::streamsize count) override {
if (_file1.is_open()) _file1.write(s,count);
saveStr.append(s, static_cast<std::size_t>(count));
// .... DO SOME MODIFICATIONS ....
if (_file2.is_open()) _file2.write(s,count);
return count;
}
private:
std::ofstream _file1{};
std::ofstream _file2{};
std::string saveStr{};
std::streambuf* saveOut = nullptr;
std::streambuf* saveErr = nullptr;
};
So I can call, for example:
int main()
{
MyStreambuf outbuf;
MyAwesomeApp();
return !outbuf.GetOutput().empty()
}
I can have the 2 files filled as well as the string, but without the content of the printf call (that remains in the console)
2. dup2
using dup2 I can redirect all the stdout (and stderr) output to a given file. so I get all the contents of std::cout AND printf. but I can Only do that in a file that I have to read (an parse) at the end.
The application may run for a long time And we want to parse outputs during execution not waiting for the end.
Is it possible to have the benefits of the streambuf approach, but capable of catching also the printf outputs?
I have a class which has a member function that opens a file, reads line by line and does some stuff to it, then writes line by line to another file. This takes some time.
I run this function in a thread. Now I want to display the progress of the function but from main without adding code to the class function that would show the progress (printf,etc).
This way I can run the class in windows or linux but with different progressbar code in main for the specific operating system.
I favor the #πάντα ῥεῖ (How do you write that!?) idea.
First we have the abstract_sink a struct that will act as interface for all ours sinks.
struct abstract_sink {
virtual void on_progress_inc(int progress) = 0;
};
Two example sinks:
struct my_sink : abstract_sink {
void on_progress_inc(int progress) {
std::cout << "The progress: " << progress << "%" << std::endl;
}
};
struct my_another_sink : abstract_sink {
void on_progress_inc(int progress) {
std::cout << "The progress: " << progress << " --- " << std::endl;
}
};
And finally a functor (See: C++ Functors - and their uses) will be implemented, this functor takes the place of your member function.
template<typename Sink>
struct process_file_functor
{
// Constructor.
process_file_functor(Sink &sink)
{
m_sink = std::make_shared<Sink>(sink);
}
void operator()(std::string infile, std::string outfile)
{
std::fstream inf(infile);
std::fstream out(outfile);
int total_lines = std::count(std::istreambuf_iterator<char>(inf), std::istreambuf_iterator<char>(), '\n');
inf.seekg(0);
int progress = 0;
for (std::string line; std::getline(inf, line); )
{
/*
Here you will do what you have to do and in every iteration
you will compute progress = 100 * lines_processed / total_lines and call...
*/
progress++;
m_sink->on_progress_inc(100 * progress/total_lines); // Here you notify the progress.
}
}
std::shared_ptr<Sink> m_sink;
};
Exmaple of use:
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <thread>
int main(int argc, char *argv[])
{
my_sink ms;
my_another_sink mas;
process_file_functor<my_sink> pfile(ms);
process_file_functor<my_another_sink> pfile1(mas);
std::thread t1(pfile, "data1.txt", "data2.txt");
std::thread t2(pfile1, "data1.txt", "data2.txt");
t1.join();
t2.join();
return 0;
}
IMPORTANT: This code don't deal with concurrency, don't use it for production is just ilustrative.
lets say we have a function which prints text to the console and in which we do not have control over the source but we are able to call it. For example
void foo() {
std::cout<<"hello world"<<std::endl;
print_to_console(); // this could be printed from anything
}
is it possible to redirect the output of the above function to a string without changing the function itself?
I'm not looking for a way to do this via terminal
Yes. That can be done. Here is a little demo:
#include <sstream>
#include <iostream>
void print_to_console() {
std::cout << "Hello from print_to_console()" << std::endl;
}
void foo(){
std::cout<<"hello world"<<std::endl;
print_to_console(); // this could be printed from anything
}
int main()
{
std::stringstream ss;
//change the underlying buffer and save the old buffer
auto old_buf = std::cout.rdbuf(ss.rdbuf());
foo(); //all the std::cout goes to ss
std::cout.rdbuf(old_buf); //reset
std::cout << "<redirected-output>\n"
<< ss.str()
<< "</redirected-output>" << std::endl;
}
Output:
<redirected-output>
hello world
Hello from print_to_console()
</redirected-output>
See Online Demo.
#Andre asked in the comment of my first answer:
What happens if they used printf, puts, write, etc ? – Andre Kostur
For printf, I came up with the following solution. It will work only on POSIX as fmemopen is available on POSIX only, but you can use temporary file instead if you want to — that will be better if you want a portable solution. The basic idea will be same.
#include <cstdio>
void print_to_console() {
std::printf( "Hello from print_to_console()\n" );
}
void foo(){
std::printf("hello world\n");
print_to_console(); // this could be printed from anything
}
int main()
{
char buffer[1024];
auto fp = fmemopen(buffer, 1024, "w");
if ( !fp ) { std::printf("error"); return 0; }
auto old = stdout;
stdout = fp;
foo(); //all the std::printf goes to buffer (using fp);
std::fclose(fp);
stdout = old; //reset
std::printf("<redirected-output>\n%s</redirected-output>", buffer);
}
Output:
<redirected-output>
hello world
Hello from print_to_console()
</redirected-output>
Online Demo.
class buffer
: public std::streambuf
{
public:
buffer(std::ostream& os)
: stream(os), buf(os.rdbuf())
{ }
~buffer()
{
stream.rdbuf(buf);
}
private:
std::ostream& stream;
std::streambuf* buf;
};
int main()
{
buffer buf(std::cout);
std::stringbuf sbuf;
std::cout.rdbuf(sbuf);
std::cout << "Hello, World\n";
}
I have a requirement, I need to use printf and cout to display the data into console and file as well.
For printf I have done it but for cout I am struggling, how to do it?
#ifdef _MSC_VER
#define GWEN_FNULL "NUL"
#define va_copy(d,s) ((d) = (s))
#else
#define GWEN_FNULL "/dev/null"
#endif
#include <iostream>
#include <fstream>
using namespace std;
void printf (FILE * outfile, const char * format, ...)
{
va_list ap1, ap2;
int i = 5;
va_start(ap1, format);
va_copy(ap2, ap1);
vprintf(format, ap1);
vfprintf(outfile, format, ap2);
va_end(ap2);
va_end(ap1);
}
/* void COUT(const char* fmt, ...)
{
ofstream out("output-file.txt");
std::cout << "Cout to file";
out << "Cout to file";
}*/
int main (int argc, char *argv[]) {
FILE *outfile;
char *mode = "a+";
char outputFilename[] = "PRINT.log";
outfile = fopen(outputFilename, mode);
char bigfoot[] = "Hello
World!\n";
int howbad = 10;
printf(outfile, "\n--------\n");
//myout();
/* then i realized that i can't send the arguments to fn:PRINTs */
printf(outfile, "%s %i",bigfoot, howbad); /* error here! I can't send bigfoot and howbad*/
system("pause");
return 0;
}
I have done it in COUT(caps, the commented part for the code above) . But I want to use normal std::cout, so how can I override it. And it should work for both sting and variables like
int i = 5;
cout << "Hello world" << i <<endl;
Or are there anyway to capture stdout data, so that they can be easily written into file and console as well.
If you have another stream buffer, you can just replace std::cout's:
std::cout.rdbuf(some_other_rdbuf);
See http://en.cppreference.com/w/cpp/io/basic_ios/rdbuf.
You can swap the underlying buffers. Here is that done facilitated through RAII.
#include <streambuf>
class buffer_restore
{
std::ostream& os;
std::streambuf* buf;
public:
buffer_restore(std::ostream& os) : os(os), buf(os.rdbuf())
{ }
~buffer_restore()
{
os.rdbuf(buf);
}
};
int main()
{
buffer_restore b(std::cout);
std::ofstream file("file.txt");
std::cout.rdbuf(file.rdbuf());
// ...
}
Overriding the behaviour of std::cout is a really bad idea as other developers will have a hard time understanding that the use of std::cout doesn't behave as usual.
Make your intention clear with a simple class
#include <fstream>
#include <iostream>
class DualStream
{
std::ofstream file_stream;
bool valid_state;
public:
DualStream(const char* filename) // the ofstream needs a path
:
file_stream(filename), // open the file stream
valid_state(file_stream) // set the state of the DualStream according to the state of the ofstream
{
}
explicit operator bool() const
{
return valid_state;
}
template <typename T>
DualStream& operator<<(T&& t) // provide a generic operator<<
{
if ( !valid_state ) // if it previously was in a bad state, don't try anything
{
return *this;
}
if ( !(std::cout << t) ) // to console!
{
valid_state = false;
return *this;
}
if ( !(file_stream << t) ) // to file!
{
valid_state = false;
return *this;
}
return *this;
}
};
// let's test it:
int main()
{
DualStream ds("testfile");
if ( (ds << 1 << "\n" << 2 << "\n") )
{
std::cerr << "all went fine\n";
}
else
{
std::cerr << "bad bad stream\n";
}
}
This provides a clean interface and outputs the same for both the console and the file.
You may want to add a flush method or open the file in append mode.
I assume you have some code using std::cout and printf which you cannot modify, otherwise the most simple way to solve your problem would be to write to a different stream from cout and use fprintf rather than or in conjunction with printf.
By following that approach you could define both a new stream class that actually wrote both to standard output and to a given file, as well as a function that combined calls to both printf and fprintf.
However a much simpler approach is to use the tee program, originally from UNIX, which copies its input both to output and to a given file. With that you could simply call your program in this way:
your_program | tee your_log_file
Answers to this question lead to a few alternative implementations available for Windows. Personally I always install cygwin on my PC's to have UNIX/Linux utilities available.
If i guess correctly you want to log everything that goes to the output also into a file.
What you want is an observer pattern.
Replace all direct logging in your code with calls to a new relay.
The logging relay sends your messages to the observers.
One of your observers loggs the message to the screen.
The other one loggs to the file.
Avoid making your relay a singleton if possible.
This suggestion only works if you can edit all of your source files.
std::cout writes to stdout file you can do the following on Linux and Windows
#include <stdio.h>
#include <iostream>
int main()
{
freopen("test.txt", "w", stdout);
std::cout << "Hello strange stdout\n";
}
to change it back use the following taken from here
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
FILE *stream ;
if((stream = freopen("file.txt", "w", stdout)) == NULL)
exit(-1);
printf("this is stdout output\n");
stream = freopen("CON", "w", stdout);
printf("And now back to the console once again\n");
}
Note: The latter is windows only
cout is normally implemented as an object instance so you can't override it in the way that you would overload / override a function or a class.
Your best bet is not to fight that - yes you could build a my_cout and #define cout my_cout but that would make your code obtuse.
For readability I'd leave cout as it is. It's a standard and everyone knows what it can and can't do.
Try using a macro - something like this (you'll need to add the includes) :
#define MY_COUT(theos,printThis) { cout << printThis ; theos << printThis; }
void test()
{
ofstream myos;
myos.open("testfile", ios::trunc|ios::out);
int i = 7;
MY_COUT(myos, "try this numbers" << i << i + 1 << endl);
myos.close()
}
There's already a Boost class for this: tee