redirect stdout/stderr to file under unix c++ - again

13,258

Solution 1

If you want to be able to reuse it, don't close stdoutfd in restore_stdout.

Solution 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

Solution 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

Solution 4

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

Solution 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.

Share:
13,258

Related videos on Youtube

carsten
Author by

carsten

Student of Particle Physics

Updated on June 04, 2022

Comments

  • carsten
    carsten almost 2 years

    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?

  • carsten
    carsten over 10 years
    thanks for your answer - however, I should have stated that I was wanting to redirect not only c++-style print statements, but also plain-c print statements using printf - which, afaik, your solution doesn't accomplish. sorry for the imprecision, I edited the question accordingly.
  • darda
    darda over 3 years
    This worked for me - now I can get the output of a third-party library I'm using. The OP's code gave me seg faults. Note you can do freopen("output.txt", "w", stdout); freopen("output.txt", "w", stderr); and get both standard out and standard error into the same file.