将数据从多个流重定向到单个流,同时保留原始数据

Redirect data from multiple streams to a single stream while keeping original data

简而言之,我正在尝试创建一个链接到文件 std::ofstream outFile{pathToFile, std::ios_base::app}; 的流。该文件是一个日志文件,理想情况下,它会接收 stderr 和 stdout 的副本。当发生错误时,例如,错误将打印在文件中的控制台中。

我试过使用 freopen(pathToFile, "a+", stderr);std::cerr.rdbuf(outFile.rdbuf());,但是,这两个都完全重定向输出,类似于 bash 中的管道。我也想在控制台中查看错误。

作为 C++ 流的新手,我不太确定如何实现这一点。我认为用另一种语言完成它的方式是“订阅”stderr,因此每次 stderr 更改并更新自身时,我的原始流都会收到通知。另一种方法是覆盖 stderr,登录到我的文件并调用原始文件,但由于程序员本身通常不调用 stderr,我不确定我该怎么做。

请注意,我使用的是 windows,因此我无法访问 unistd.h。我还想避免使用 STL 或第三方库。

IOStreams 在内部使用 std::streambuf 来实际写入(或读取)字符。如果你只是想重定向所有写入另一个流的字符,你可以只重定向相应的流缓冲区。不过,您最终应该恢复原始流缓冲区,因为流在​​销毁时会被刷新,并且流缓冲区的生命周期很重要。例如

 #include <iostream>
 #include <fstream>

 struct redirect {
     std::ostream&   d_stream;
     std::streambuf* d_orig;
     redirect(std::ostream& out, std::ostream& to)
         : d_stream(out)
         , d_orig(out.rdbuf(to.rdbuf())) {
     }
     ~redirect() { this->d_stream.rdbuf(this->d_orig); }
};

int main() {
    std::ofstream log("my-log.txt");
    redirect rcout(std::cout, log);
    redirect rcerr(std::cerr, log);
    std::cout << "hello, ";
    std::cerr << "world!\n";
}

如果您想要重定向的流出现在原始流上,您可以使用“teestream”,它使用流缓冲区将每个字符复制到两个不同的流缓冲区(我过去曾在多个地方发布过此类流的多个版本,包括 Whosebug)。