【问题标题】:redirect stdout/stderr to file under unix c++ - again将 stdout/stderr 重定向到 unix c++ 下的文件 - 再次
【发布时间】:2013-08-07 19:33:12
【问题描述】:

我想做的事

从 c++ 内部将 stdout 和 stderr 重定向到一个或多个文件

我为什么需要它

我正在使用一个外部的、预编译的第三方库,它会产生大量的输出,我想将其重定向到一个日志文件以保持控制台清洁。

条件

兼容性不是问题,代码只能在 Unix 系统上运行。重定向不仅应该影响 c++ 样式的打印 (std::cout << "hello world" << std::endl),还应该影响 c 样式的打印 (printf("hello world\n"))。

到目前为止我已经尝试过什么

我在stackoverflow上浏览了半天,阅读了许多有类似问题的人的答案。在这些答案的帮助下,我已经能够整理出以下代码:


#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;
}

我希望看到的:

visible 1
visible 2

我实际看到的

visible 1

也就是说,当第一次使用这个机制时,它可以工作 - 但如果再次使用,恢复输出将不起作用。 有人可以向我指出我需要改变什么才能让机制无限频繁地工作吗?

【问题讨论】:

标签: c++ c io file-descriptor io-redirection


【解决方案1】:

如果您希望能够重复使用它,请不要在restore_stdout 中关闭stdoutfd

【讨论】:

    【解决方案2】:

    除了freopen()afr0ck答案我想说的是,在使用freopen()时我们应该小心。一旦像 stdoutstdin 这样的流被重新打开并分配新的目的地(此处为 'output.txt' 文件),它始终保留给程序,除非它已被明确更改。

    freopen("output.txt", "a", stdout);
    

    这里标准输出流stdout 被重新打开并分配有'output.txt' 文件。之后,每当我们使用printf() 或任何其他stdout 流(如-putchar())时,每个输出都会转到'output.txt'。要恢复printf()putchar() 的默认行为(即在控制台/终端中打印输出),我们可以使用以下代码行 -

    • 对于 gcc,Linux 发行版,如 ubuntu - freopen("/dev/tty", "w", stdout);
    • 对于 Mingw C/C++, windows - freopen("CON", "w", stdout);

    参见下面的代码示例 -

    #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");        
    
    }
    

    这段代码会在你的当前目录中生成一个'output.txt'文件,并且将在'output.txt'中打印No#2和No#3文件。

    谢谢

    【讨论】:

    • 这对我有用 - 现在我可以获得我正在使用的第三方库的输出。 OP 的代码给了我段错误。请注意,您可以执行 freopen("output.txt", "w", stdout); freopen("output.txt", "w", stderr); 并将标准输出和标准错误都放入同一个文件中。
    【解决方案3】:

    你在寻找这样的东西吗:-

    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); 
    
    }
    

    来自我之前的answer

    【讨论】:

    • 感谢您的回答-但是,我应该声明我不仅希望重定向 c++ 样式的打印语句,还希望使用 printf 重定向纯 c 打印语句-afaik,您的解决方案没有不成。抱歉不准确,我相应地编辑了问题。
    【解决方案4】:

    我最好使用 freopen()

    使用语法:

    freopen("RedToFile","r",stdout);
    or
    freopen("/dev/null","a",stdout);
    

    “stderr”也是如此

    【讨论】:

      【解决方案5】:

      对于 C++ iostream,您可以使用 rdbuf 的非常量重载 将std::cout 设置为std::filebuf。 (这最好由 RAII类的手段,因为你必须先恢复它 离开main。)对于C FILE*,你可以使用freopen,但是 我认为您无法恢复它。

      FWIW:这两种解决方案都只使用标准 C++ 或 C,所以 应该是便携的。

      【讨论】:

        【解决方案6】:

        我受到@POW 和@James Kanze 的回答的启发,并整理了一个用于将std::cout 重定向到文件的小RAII 类。它旨在演示该原理。

        代码:

        #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.txt"

        此消息转到文件

        【讨论】:

          猜你喜欢
          • 2014-07-22
          • 2019-10-17
          • 2016-02-19
          • 1970-01-01
          • 2011-12-28
          • 1970-01-01
          • 1970-01-01
          • 2022-01-18
          • 1970-01-01
          相关资源
          最近更新 更多