C++关于std::cerr\cout\cin的重定向(二)

2021年03月18日 429点热度 0人点赞 0条评论

之前尝试重定向std输出语句,并没有找到合适解决重定向时如何捕获输出事件的问题,只能使用定时器定时的检测缓冲区中的内容。

《关于std::cerr\cout\cin的重定向》

之后我在一个开源项目的代码中找到一个方案可以完美的解决这个问题。

使用这个方法首先得先了解流缓冲区std::streambuf。流缓冲区是负责它所关联的流对象所有写入、读取操作的对象,流对象会将输入输出操作都委托给缓冲区对象,将缓冲区当作一个流对象与输入输出之间的一个中介。

std::streambuf的详细介绍,戳一戳

这里主要关注sync()和overflow()这两个虚函数。

int sync();

这个函数用于将流中的内容与设备中的的内容同步。返回0表示成功,-1表示失败。经过简单的测试在相关联的流对象进行输入输出操作的时候会被调用。

int overflow (int c = EOF);

文档中提到这个函数是用于将字符放入一个一个的放入设备中,但是比较奇怪的是函数的参数确实int类型,按理说应该是char类型才对,好在这里使用c风格的强制类型转换,将之转换为char类型使用时完全没有问题的。
函数执行成功将返回被输出的字符,失败则返回EOF。
补充:这里参数使用int类型可能时为了这里能使用EOF这个宏

#define EOF (-1)

知道了这些思路就渐渐清晰了,前一篇博文都是直接获取流对象的缓冲区去替换std::cerr的缓冲区,然后去捕获流对象的输入输出语句。
然后这里直接生命一个缓冲区类继承std::streambuf,然后重写overflow()和sync()函数。



#include <iostream>
#include <fstream>
#include <streambuf>

class MyBuf :public std::streambuf{
public:
MyBuf(){
buffer.reserve(8);
}
protected:
int overflow(int c = EOF){
if (c != EOF)
buffer.push_back((char)c);
return c;
}
int sync(){
if (!buffer.empty())
{
std::cout <<"This is redirection "<<"(" << buffer.c_str() << ")" <<std::endl;
buffer.clear();
}
return 0;
}
private:
std::string buffer;

};

int main(){
MyBuf *buf = new MyBuf;
std::cerr.rdbuf(buf);
std::cerr << "hello" << std::endl;
std::cerr << "cmake" << std::endl;
std::cerr << "!" << std::endl;
std::cin.get();
return 0;
}

输出

This is redirection (hello)
This is redirection (
)
This is redirection (cmake)
This is redirection (
)
This is redirection (!)
This is redirection (
)

看到这里的输出也明白sync()函数会在使用<<操作符的时候被调用了。标准库里大多数输出语句都可以用这样的方式重定向,嗯,利用这个给自己的软件写一个日志框架也是不错的。

大脸猫

半个C++程序员。

文章评论