我需要将一个 ofstream 重定向到一个文件并为打印的每一行加上时间戳。 (它是日志系统的一部分)。
我有一个工作类设法做到这一点,但它拒绝在发出 std::endl 时刷新文件。我很感激任何帮助。 (如果有更简单的方法,请告知)。
#include <iostream>
#include <streambuf>
#include <fstream>
#include <sys/time.h>
#include <cstring>
#include <memory>
class TimeStampBuf: public std::streambuf {
public:
explicit TimeStampBuf(std::streambuf* dest) :
_dest(dest),
_isAtStartOfLine(true),
_owner( NULL) {
}
explicit TimeStampBuf(std::ostream& dest) :
_dest(dest.rdbuf()),
_isAtStartOfLine(true),
_owner(&dest) {
_owner->rdbuf(this);
}
virtual ~TimeStampBuf() {
if (_owner != NULL) {
_owner->rdbuf(_dest);
}
}
protected:
virtual int overflow(int ch) {
if (_isAtStartOfLine) {
char timebuff[30];
timeval curTime;
gettimeofday(&curTime, NULL);
strftime(timebuff, sizeof(timebuff), "%Y-%m-%d %H:%M:%S:",
localtime(&curTime.tv_sec));
sprintf(timebuff + strlen(timebuff), "%03u\t",
(unsigned int) curTime.tv_usec / 1000);
_dest->sputn(timebuff, strlen(timebuff));
}
_isAtStartOfLine = ch == '\n';
return _dest->sputc(ch);
}
private:
std::streambuf *_dest;
bool _isAtStartOfLine;
std::ostream *_owner;
};
class OutputRedirectAndStamp {
public:
OutputRedirectAndStamp(std::string file, std::ostream &s = std::cout, std::ios::openmode mode = std::ios::out){
_s=&s;
_file=file;
if(_file.size()){
_mode=mode;
_buf.open(file.c_str(),mode);
_coutBuf = s.rdbuf((std::streambuf*)&_buf);
}
_tsb.reset(new TimeStampBuf(s));
}
void reopen(void){
_tsb.reset();
if(_file.size()){
_s->rdbuf(_coutBuf); //reset to previous output
_buf.close();
_buf.open(_file.c_str(),_mode);
_coutBuf = _s->rdbuf((std::streambuf*)&_buf);
}
_tsb.reset(new TimeStampBuf(*_s));
}
~OutputRedirectAndStamp() {
_tsb.reset();
if(_file.size()){
_s->rdbuf(_coutBuf); //reset to previous output
}
}
private:
std::string _file;
std::ios::openmode _mode;
std::ostream *_s;
std::filebuf _buf;
std::streambuf *_coutBuf;
std::unique_ptr<TimeStampBuf> _tsb;
};
int main() //example main
{
std::unique_ptr<OutputRedirectAndStamp> a;
a.reset(new OutputRedirectAndStamp("test.txt",std::cout,std::ios::app | std::ios::out));
std::cout<<"this is written to file"<<2<<std::endl;
a->reopen();
std::cout<<"this is written to file also"<<std::endl;
a.reset();
std::cout<<"this is written to stdout"<<std::endl;
return 0;
}
最佳答案
当您刷新 std::ostream
时,流缓冲区的 pubsync()
被调用,后者又调用 virtual
函数 同步()
。如果您不覆盖 sync()
,它只会通过返回 0
来声明它已成功。从你的 sync()
覆盖你应该只调用保持流缓冲区的 pubsync()
:
int TimeStampBuf::sync() {
return _dest->pubsync();
}
关于c++ - 重定向和时间戳 std::cout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19305656/