我想做什么
将stdout和stderr重定向到c ++中的一个或多个文件
为什么我需要它
我正在使用外部预编译的第三方库,它会产生大量的输出,我想将其重定向到日志文件以保持控制台清洁。
条件
兼容性不是问题,代码只能在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
也就是说,第一次使用这种机制时,它可以工作 - 但如果再次使用,恢复输出将不起作用。 有人可以向我指出我需要改变什么才能让机制经常无限地工作吗?
答案 0 :(得分:4)
如果您希望能够重复使用它,请不要关闭stdoutfd
中的restore_stdout
。
答案 1 :(得分:2)
你在寻找这样的东西: -
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
答案 2 :(得分:2)
我会更好地使用freopen()
用法语法:
freopen("RedToFile","r",stdout);
or
freopen("/dev/null","a",stdout);
“stderr”也是如此
答案 3 :(得分:1)
除了afr0ck的freopen()回答之外,我想说在使用freopen()
时我们应该小心。通过分配新目标(此处为&#39; output.txt&#39; 文件)重新打开stdout
或stdin
之类的流后,它始终保留给程序除非它已经明确改变。
freopen("output.txt", "a", stdout);
此处重新打开标准输出流stdout
,并使用&#39; output.txt&#39; 文件进行分配。在此之后,只要我们使用printf()
或任何其他stdout
流,例如 - putchar()
,那么每个输出都将转到&#39; output.txt&#39; 。要恢复printf()
或putchar()
的默认行为(即在控制台/终端中打印输出),我们可以使用以下代码行 -
freopen("/dev/tty", "w", stdout);
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");
}
此代码会在当前目录中生成&#39; output.txt&#39; 文件,并且&#39;中将显示No#2和No#3; output.txt&#39; 文件。
由于
答案 4 :(得分:0)
对于C ++ iostream,您可以使用rdbuf
的非常量重载
将std::cout
设置为std::filebuf
。 (最好这样做
RAII类的手段,因为你必须先恢复它
离开main。)对于C FILE*
,您可以使用freopen
,但是
我认为你无法恢复它。
FWIW:这两种解决方案都只使用标准C ++或C,所以 应该是便携式的。
答案 5 :(得分:0)
我受到@POW和@James Kanze的回答的启发,并整理了一个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"
的内容:
此消息进入文件