In C/C++ the standard output streams: stdout/stderr,std::cout/std::cerr print to the console (not to mention clog, wcout...). These can be independently redirected from the command line.
Is there a way to add an alternative output stream that:
Prints to the console like the standard streams;
Does not get redirected with either of the standard streams.
In particular, I am interested in having some console output that does not get logged by redirection.
If there are no standard ways, then platform dependent ways (Linux and Windows) will also be helpful.
On Linux systems, you might open /dev/tty and write to it. See tty(4). Read also console(4) and perhaps consider /dev/console (but I recommend /dev/tty)
AFAIK, the C++ standard does not define such an output stream.
See also (on Posix) syslog(3) which would be my preference (since /dev/tty wont work if you have no controlling terminal).
Following up on #BasileStarynkevitch suggestions, the same can be done on Windows replacing "dev/tty" with "con".
For completeness here's a full program demonstrating non-redirectable calls:
#include <stdio.h>
#include <iostream>
#include <fstream>
#ifndef DEVTTY
#define DEVTTY "con" // on Windows
// #define DEVTTY "/dev/tty" // on Linux/MacOS
#endif
using namespace std;
int main()
{
cout << "DEVTTY = " << DEVTTY << endl;
printf("Print[f]ed to stdout.\n");
fprintf(stdout, "Print[f]ed to stdout.\n");
cout << "Printed to std::cout" << endl;
fprintf(stderr, "Print[f]ed to stderr.\n");
cerr << "Printed to std::cerr" << endl;
{
// C, stdio version
FILE* fd = fopen(DEVTTY, "w");
fprintf(fd, "Printed to \"%s\"\n", DEVTTY); // will not be redirected
fclose(fd);
}
{
// C++, fstream version
std::ofstream ofs(DEVTTY);
ofs << "Printed via std::ofstream to \"" << DEVTTY << "\"" << endl; // will not be redirected
}
return EXIT_SUCCESS;
}
Redirecting both stdout and stderr as in StreamRedirection.exe > out.txt 2>&1 gives:
In out.txt:
DEVTTY = con
Print[f]ed to stdout.
Print[f]ed to stdout.
Printed to std::cout
Print[f]ed to stderr.
Printed to std::cerr
and in the Console (on Windows):
Printed to "con"
Printed via std::ofstream to "con"
Related
when I use this simple program to get the standard output of the process, I also somehow get the standard error of the process, although the man page for popen says that only the standard output is redirected. Is it possible that this is related to the shell that is used when forking a process with popen? errEr is a simple program outputting to stderr (cerr << "hello";). I'm using RHEL 6.4. Thanks!
#include <iostream>
#include <cstdio>
using namespace std;
int main ()
{
FILE *fd = popen("errWr", "r");
char str [1024];
while (fgets(str, 1024, fd))
{
cout<<str<<endl;
}
return 0;
}
You're not getting the output from stderr in your program using popen.
Following simple example shows, that error stream from started application is printed in terminal, without being read in your program. popen redirects only stdout stream and stderr stream is not affected, so it's just printed to terminal.
#include <iostream>
#include <cstdio>
using namespace std;
int main ()
{
FILE *fd = popen("errWr", "r");
char str [1024];
while (fgets(str, 1024, fd))
{
cout << "=>" << str << "<=" << endl;
}
return 0;
}
What I want to do
redirect stdout and stderr to one or more files from inside c++
Why I need it
I am using an external, precompiled third-party library that produces a ridiculous amount of output, which I would like to redirect to a log file to keep the console clean.
Conditions
Compatibility is not a problem, the code will only run on Unix systems. The redirection should not only affect c++-style printing (std::cout << "hello world" << std::endl), but also c-style printing (printf("hello world\n")).
What I have tried so far
I have been browsing on stackoverflow for half a day, reading multiple answers to people having similar problems. With the help of these answers, I have been able to put together the following piece of code:
#include <stdio.h>
#include <iostream>
#include <fcntl.h>
#include "unistd.h"
const int stdoutfd(dup(fileno(stdout)));
int redirect_stdout(const char* fname){
fflush(stdout);
int newstdout = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
dup2(newstdout, fileno(stdout));
close(newstdout);
}
int restore_stdout(){
fflush(stdout);
dup2(stdoutfd, fileno(stdout));
close(stdoutfd);
return stdoutfd;
}
int main(){
redirect_stdout("/dev/null");
std::cout << "invisible 1" << std::endl;
restore_stdout();
std::cout << "visible 1" << std::endl;
redirect_stdout("/dev/null");
std::cout << "invisible 2" << std::endl;
restore_stdout();
std::cout << "visible 2" << std::endl;
return 0;
}
What I would expect to see:
visible 1
visible 2
What I actually see
visible 1
That is, when using this mechanism for the first time, it works - but if used again, restoring the output will not work.
Can somebody point out to me what I need to change in order to have the mechanism work infinitely often?
EDIT: Why it is different from what everyone else is doing?
Many people have similar questions (hence the "again", e.g. here). However, here, I specifically target a solution that works for C-style and C++-style printing, and have a particular focus on the reusability of the functions - something that is generally not addressed in other questions and answers.
In addition to afr0ck answer of freopen() I want to say that while using freopen() we should be careful. Once a stream like stdout or stdin is reopened with assigning the new destination(here the 'output.txt' file) always it remains for a program unless it has been explicitly change.
freopen("output.txt", "a", stdout);
Here the standard output stream stdout is reopened and assigned with the 'output.txt' file. After that whenever we use printf() or any other stdout stream like - putchar() then every output will goes to the 'output.txt'. To get back the default behavior (that is printing the output in console/terminal) of printf() or putchar() we can use the following line of code -
for gcc, linux distribution like ubuntu - freopen("/dev/tty", "w", stdout);
for Mingw C/C++, windows - freopen("CON", "w", stdout);
See the code example below -
#include <stdio.h>
int main() {
printf("No#1. This line goes to terminal/console\n");
freopen("output.txt", "a", stdout);
printf("No#2. This line goes to the \"output.txt\" file\n");
printf("No#3. This line aslo goes to the \"output.txt\" file\n");
freopen("/dev/tty", "w", stdout); /*for gcc, diffrent linux distro eg. - ubuntu*/
//freopen("CON", "w", stdout); /*Mingw C++; Windows*/
printf("No#4. This line again goes to terminal/console\n");
}
This code generate a 'output.txt' file in your current directory and the No#2 and No#3 will be printed in the 'output.txt' file.
Thanks
If you want to be able to reuse it, don't close stdoutfd in restore_stdout.
Are you looking for something like this :-
int main()
{
// Save original std::cin, std::cout
std::streambuf *coutbuf = std::cout.rdbuf();
std::streambuf *cinbuf = std::cin.rdbuf();
std::ofstream out("outfile.txt");
std::ifstream in("infile.txt");
//Read from infile.txt using std::cin
std::cin.rdbuf(in.rdbuf());
//Write to outfile.txt through std::cout
std::cout.rdbuf(out.rdbuf());
std::string test;
std::cin >> test; //from infile.txt
std::cout << test << " "; //to outfile.txt
//Restore back.
std::cin.rdbuf(cinbuf);
std::cout.rdbuf(coutbuf);
}
From my earlier answer
well i u'd better use freopen()
Usage Syntax:
freopen("RedToFile","r",stdout);
or
freopen("/dev/null","a",stdout);
the same goes for "stderr"
For C++ iostreams, you can use the non-const overload of rdbuf
to set std::cout to a std::filebuf. (This is best done by
means of an RAII class, since you have to restore it before
leaving main.) For C FILE*, you can use freopen, but
I don't think you'll be able to restore it.
FWIW: both of these solutions use only standard C++ or C, so
should be portable.
I was inspired by #POW and #James Kanze 's answers and put together a little RAII class for redirecting std::cout to a file. It is intended to demonstrate the principle.
Code:
#include <iostream>
#include <fstream>
#include <string>
// RAII for redirection
class Redirect {
public:
explicit Redirect(const std::string& filenm):
_coutbuf{ std::cout.rdbuf() }, // save original rdbuf
_outf{ filenm }
{
// replace cout's rdbuf with the file's rdbuf
std::cout.rdbuf(_outf.rdbuf());
}
~Redirect() {
// restore cout's rdbuf to the original
std::cout << std::flush;
_outf.close(); ///< not really necessary
std::cout.rdbuf(_coutbuf);
}
private:
std::streambuf* _coutbuf;
std::ofstream _outf;
};
// == MAIN ==
int main(int argc, char* argv[]) {
std::cout << "This message is printed to the screen" << std::endl;
{
// scope for the redirection
Redirect redirect{ "output.txt" };
std::cout << "This message goes to the file" << std::endl;
}
std::cout << "Printing to the screen again" << std::endl;
}
Output:
This message is printed to the screen
Printing to the screen again
Contents of the file "output.txt":
This message goes to the file
I'm trying to redirect some of the standard output to a text file, and some other to the command prompt.
I'm currently outputting all of it to a file, but I'd like to output some to the command prompt, so I can know at least (get some hits), on what's been recorded (since it takes like 10 minutes to run this code)
This is what I'm doing;
FILE *stream ;
std::stringstream ss;
ss << "K_file.txt";
if((stream = freopen(ss.str().c_str(), "w", stdout)) == NULL)
exit(-1);
std::cout<<"blah blah blah...";
Edit based on comment;
'some' is part of the code where I would like to explicitly specify, example;
for(int i = 0; i<1000; i++)
{
std::cout<<"I would like this to go to the file - since it's detailed";
}
std::cout<<"loop finished - I would like this to go to the command prompt";
This might not be the best example but I hope you get the point.
You could "abuse" standard output and standard error stream for that. For example:
#include <iostream>
void main() {
std::cout << "standard output";
std::cerr << "standard error";
}
Now, if you redirect just the standard error to file...
your_program.exe 2> file.txt
...you'll get "standard output" in console window and "standard error" in file.txt.
(NOTE: This is Windows redirection syntax - I'm sure you'll have no trouble doing redirection on other OSes if you need to.)
I think this might help:
#include <fstream>
#include <iostream>
class stream_redirector {
public:
stream_redirector(std::ostream& dst, std::ostream& src)
: src(src), sbuf(src.rdbuf())
{
src.rdbuf(dst.rdbuf());
}
~stream_redirector() {
src.rdbuf(sbuf);
}
private:
std::ostream& src;
std::streambuf* const sbuf;
};
int main() {
std::ofstream log("log.txt");
std::cout << "Written to console." << std::endl;
{
// We redirect std::cout to log.
stream_redirector redirect(log, std::cout);
std::cout << "Written to log file" << std::endl;
// When this scope ends, the destructor will undo the redirection.
}
std::cout << "Also written to console." << std::endl;
}
I realize that ofstream doesn't work on Windows 7 hidden file.
Here is the quick test code.
#include <fstream>
#include <iostream>
#include <tchar.h>
#include <windows.h>
int main() {
{
std::ifstream file2(_T("c:\\a.txt"));
if (file2.is_open()) {
std::cout << "ifstream open" << std::endl;
} else {
std::cout << "ifstream not open!" << std::endl;
}
}
// SetFileAttributes(_T("c:\\a.txt"), FILE_ATTRIBUTE_NORMAL);
SetFileAttributes(_T("c:\\a.txt"), FILE_ATTRIBUTE_HIDDEN);
{
std::ofstream file(_T("c:\\a.txt"));
if (file.is_open()) {
std::cout << "ofstream open" << std::endl;
} else {
std::cout << "ofstream not open!" << std::endl;
}
}
getchar();
}
Here is the output I am getting
ifstream open
ofstream not open!
If I am using FILE_ATTRIBUTE_NORMAL, ofstream will be opened successfully.
I do not run the program as Administrator. But, I do use the following linker option.
Having to turn No for Enable User Account Control (UAC) is important, if we do not start the application as Administrator. OS will help us to write the actual file to C:\Users\yccheok\AppData\Local\VirtualStore\a.txt instead of protected C:\
Does ofstream fail on Windows 7 hidden file, is an expected behaviour?
Yes. As noted in the underlying CreateFile documentation, " If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile fails and sets the last error to ERROR_ACCESS_DENIED if the file exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute."
Or more readable: CreateFile fails if both CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, and if the file has the FILE_ATTRIBUTE_HIDDEN and/or FILE_ATTRIBUTE_SYSTEM attribute.
It just so happens that ofstream calls CreateFile like this.
I'm trying to use the ofstream class to write some stuff to a file, but all that happens is that the file gets created, and then nothing. I have some simply code here:
#include <iostream>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <time.h>
using namespace std;
int main(int argc, char* argv[])
{
ofstream file;
file.open("test.txt");
if (!file) {
cout << strerror(errno) << endl;
} else {
cout << "All is well!" << endl;
}
for (int i = 0; i < 10; i++) {
file << i << "\t" << time(NULL) << endl;
}
file.flush();
file.close();
return 0;
}
When I create a console application, everything works fine, so I'm afraid this code is not completely representative. However, I am using code like this in a much larger project that - to be honest - I don't fully understand (Neurostim). I'm supposed to write some class that is compiled to a dll which can be loaded by Neurostim.
When the code is run, "test.txt" is created and then "No error!" is printed, as this is apparently the output from strerror. Obviously this is wrong however. The application runs perfectly otherwise, and is not phased by the fact that I'm trying to write to a corrupted stream. It just doesn't do it. It seems to me like there is no problem with permissions, because the file is in fact created.
Does anyone have any ideas what kind of things might cause this odd behavior? (I'm on WinXP Pro SP3 and use Visual C++ 2008 Express Edition)
Thanks!
Just a thought :- in your real code are you re-using your stream object?
If so, you need to ensure that you call clear() on the stream before re-using the object otherwise, if there was a previous error state, it won't work. As I recall, not calling clear() on such a stream would result in an empty file that couldn't be written to, as you describe in your question.
ofstream file;
file.open("test.txt");
Just a nit: you can combine that into a single line. ofstream file("test.txt");
if (file) {
cout << strerror(errno) << endl;
} else {
cout << "All is well!" << endl;
}
Your test is backwards. If file is true, it's open and ready for writing.
Also, I wouldn't count on strerror() working correctly on Windows. Most Windows APIs don't use errno to signal errors. If your failure is happening outside the C/C++ run-time library, this may not tell you anything interesting.
UPDATE Thinking more about this, failing to open a file via fstreams is not guaranteed to set errno. It's possible that errno ends up set on some platforms (espeically if those platforms implement fstream operations with FILE* or file descriptors, or some other library that sets errno) but that is not guaranteed. The official way to check for failure is via exceptions, std::io_state or helper methods on std::fstream (like fail or bad). Unfortunately you can't get as much information out of std::streams as you can from errno.
You've got the if statement wrong. operator void* returns NULL (a.k.a. false) if the file is not writable. It returns non-zero (a.k.a. true) if the file is writeable. So you want:
if (!file) {
cout << strerror(errno) << endl;
} else {
cout << "All is well!" << endl;
}
Or:
if (!file.good()) {
cout << strerror(errno) << endl;
} else {
cout << "All is well!" << endl;
}