重定向stdout/stderr到unix c++下的文件-再次[重复]

vfwfrxfs  于 2023-01-12  发布在  Unix
关注(0)|答案(6)|浏览(161)
    • 此问题在此处已有答案**:

C++: Redirecting STDOUT(7个答案)
6个月前关闭。
这篇文章是昨天编辑并提交审查的。
"我想做的事"
从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

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

    • 编辑:为什么它与其他人正在做的事情不同?**

许多人都有类似的问题(因此有了"再次",例如here)。然而,在这里,我特别针对一个适用于C风格和C++风格打印的解决方案,并特别关注函数的可重用性-这在其他问题和答案中通常没有解决。

kyvafyod

kyvafyod1#

除了freopen()afr0ck答案之外,我想说的是,当使用freopen()时,我们应该小心。一旦像stdoutstdin这样的流被重新打开并分配了新的目标(这里是**'output.txt'**文件),它总是为程序保留,除非它被显式地更改。

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

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

  • 对于gcc,Linux发行版如ubuntu -freopen("/dev/tty", "w", stdout);
  • 对于明w C/C++,窗口-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”文件,并且No#2和No#3将在“output.txt”**文件中打印。
谢谢

z8dt9xmd

z8dt9xmd2#

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

e4yzc0pl

e4yzc0pl3#

你在找这样的东西吗

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

}

根据我之前的回答

klh5stk1

klh5stk14#

那么我最好使用freopen()
用法语法:

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

“stderr”也是如此

dz6r00yl

dz6r00yl5#

对于C++ iostreams,您可以使用rdbuf的非常数重载将std::cout设置为std::filebuf。(最好通过RAII类来完成,因为您必须在离开main之前恢复它。)对于C FILE*,您可以使用freopen,但我不认为您能够恢复它。
FWIW:这两种解决方案都只使用标准的C++或C,所以应该是可移植的。

xghobddn

xghobddn6#

@POW和@JamesKanze的回答启发了我,我编写了一个RAII类,用于将std::cout重定向到一个文件,目的是演示这个原理。
代码:

#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"的内容:
此消息转到文件

相关问题