问题
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?
回答1:
If you want to be able to reuse it, don't close stdoutfd
in restore_stdout
.
回答2:
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
回答3:
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
回答4:
well i u'd better use freopen()
Usage Syntax:
freopen("RedToFile","r",stdout);
or
freopen("/dev/null","a",stdout);
the same goes for "stderr"
回答5:
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.
来源:https://stackoverflow.com/questions/18086193/redirect-stdout-stderr-to-file-under-unix-c-again