2013-10-10 85 views
0

我需要將一個ofstream重定向到一個文件併爲每一行打印時間戳。 (這是測井系統的一部分)。重定向和時間戳std :: cout

我有一個工作類,它可以做到這一點,但它拒絕在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; 
} 
+0

你可能會得到更多的幫助,如果你能減少你的代碼,只是需要什麼重現該問題。儘可能地儘可能地切斷,這將使我們更容易幫助您找到解決方案。 –

+1

如果Boost.Iostreams可供您使用,它會嚴重減少您的工作量。 – GManNickG

+0

我之前用過boost。我會看看Iostreams庫,但不幸的是它不適合這個特定的項目。謝謝你的消化。 – user1783395

回答

2

當你刷新的std::ostream,流緩衝的pubsync()被稱爲這反過來又調用virtual功能sync()。如果您不覆蓋sync()它只會聲稱它成功返回0。從你sync()覆蓋你應該叫召開流緩衝區的pubsync()

int TimeStampBuf::sync() { 
    return _dest->pubsync(); 
} 
+0

這完全解決了這個問題。謝謝! – user1783395