2009-06-15 94 views
1

我正在寻找一种方法来将从istream(cin,在我的情况下)读取的输入分支(tee)输出到日志文件(clog)/ofstream /等),同时仍然使用输入进行处理。将输入(cin)输出到日志文件(或阻塞)

我已阅读关于boost :: tee_device,它与我的要求非常相似。不幸的是,它被实现为一个ostream,从而解决了“管道的另一端”类似的问题。

我试图编写一个istream(adapter)类,它将输入函数转发到一个包装输入流(cin),并且还将读取的内容发送到日志文件。

这适用于直接调用操作符>>(...)的基本类型,但是,我遇到了一些更高级的输入流使用问题,例如,对于操作符>>(std ::字符串)和std :: string getline函数。

有没有更简单的方法来做到这一点(可能通过rdbuf()操作)?

谢谢!

编辑:我可以改变我的代码到处都是这样的:cin >> value; clog < < value; - 但这将是一个重大而丑陋的变化。我还希望有一个简单的方法来关闭注销。因此,我想要一种方法来将此模型化为一个istream“过滤器”,然后简单地将所有对cin的引用替换为这个istream“记录器”。

理想的解决方案:

class log_istream : public std::istream 
{ 
public: 
    log_istream(std::istream & in , std::ostream & out); 

    /* ... istream forwarding functions ... */ 

private: 
    std::istream & in_; 
    std::ostream & out_;  
}; 

int main() { 
    log_istream logger(std::cin , std::ofstream("logfile.out")); 

    logger >> value; // this implies infile >> value and logfile << value 
    getline(logger,my_string); // this also implies logfile.writeline(value) 
    // etc 
} 

+0

我试着做什么,你在帖子中写道以上在同一时间,和它一直工作,直到特殊字符达到(如endl),然后班级按预期停止工作。我期待在这里看到答案。 – 2009-06-15 21:23:59

+0

这些帮助:[http://stackoverflow.com/questions/999120/c-hello-world-boost-tee-example-program](http://stackoverflow.com/questions/999120/c-hello-world -boost-tee-example-program) [http://stackoverflow.com/questions/670465/using-boostiostreamsteedevice](http://stackoverflow.com/questions/670465/using-boostiostreamsteedevice) – stefanB 2009-06-16 02:06:27

回答

1

最终的答案:

#ifndef TEE_ISTREAM_H_ 
#define TEE_ISTREAM_H_ 

/*****************************************************************************/ 

#include <boost/iostreams/tee.hpp> 
#include <boost/iostreams/invert.hpp> 
#include <boost/iostreams/device/file.hpp> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/tr1/memory.hpp> 
#include <iostream> 

/*****************************************************************************/ 

namespace bio = boost::iostreams; 

/*****************************************************************************/ 

class tee_source : public bio::source { 
public: 
    tee_source(std::istream & in, const std::string & filename) 
     : in_(in), log_file_(filename, std::ios::app), tee_(bio::tee(log_file_), 1) 
    { } 

    std::streamsize read(char* s, std::streamsize n) 
    { 
     return tee_.read(in_,s,n); 
    } 

private: 
    std::istream &        in_; 
    bio::file         log_file_; 
    bio::inverse< bio::tee_filter<bio::file> > tee_; 
}; 

/*****************************************************************************/ 

typedef bio::filtering_istream    tee_istream_t; 
typedef std::tr1::shared_ptr<tee_istream_t> tee_istream_ptr_t; 

/*****************************************************************************/ 

inline tee_istream_ptr_t make_tee_istream(std::istream & in, const std::string & filename) 
{ 
    return tee_istream_ptr_t(new tee_istream_t(tee_source(in , filename), 0)); 
} 

/*****************************************************************************/ 

#endif 
3

使用了Boost.Iostreams,你可以定义一个输入滤波器,它记录它读入堵塞。喜欢的东西:

(警告:今后未经测试的代码)

class LoggingInputFilter : public multichar_input_filter { 
public: 
    template<typename Source> 
    std::streamsize read(Source& Src, char* S, std::streamsize N) 
    { 
     streamsize result = read(Src, S, N); 
     if (result == -1){ 
      return result; 
     } 

     if (std::clog.write(S, result)){ 
      return result; 
     } 

     return -1; 
    } 
}; 

性病IT连锁:: CIN:

LoggingInputFilter cin_logger; 
filtering_stream logged_cin(cin_logger); 
logged_cin.push(std::cin); 

,而使用logged_cin的std :: CIN的

编辑:或者在streabuf级别运行,以便您的代码仍然使用std :: cin:

LoggingInputFilter cin_logger; 
filtering_streambuf logged_cin(cin_logger); 
logged_cin.push(std::cin.rdbuf()); 
std::cin.rdbuf(logged_cin); 
+0

这不是我用过的解决方案 - 但这正是让我走上正轨的原因。谢谢! – mmocny 2009-06-16 15:45:20

1

我找到了一个简单的解决方案:

Boost :: iostreams提供源/汇滤波器之间的反转。

虽然tee_filter建模为一个接收器,就可以颠倒()它变成一个来源,它仍然会“三通”是什么过滤到水槽规定:

boost::iostreams::file log_file("sample.txt", std::ios::trunc); // or std::ios::app 

    // Single parameter tee() function returns a tee_filter , and invert() inverts that filter 
    boost::iostreams::filtering_istream in(
      boost::iostreams::invert(
        boost::iostreams::tee(log_file))); 

这样,我有记录在所有过滤的输入上。

表现不是问题,但如果有人注意到任何红旗,我会非常感兴趣。谢谢。

0

尼斯易/一小段路(需要安装最新版本的升压我猜和-std = C++ 11) - 由于@mmocny,@埃里克Malenfant和Boost LIB开发者。

这个演示程序日志“tmp.log”你有什么谈话给std :: cin和std ::法院:

#include <iostream> 

#include <boost/iostreams/tee.hpp> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/iostreams/device/file.hpp> 

namespace bio = boost::iostreams; 

int main(int, char**) 
{ 
    // Logging 
    bio::filtering_ostream log; 
    log.push(bio::file_sink("tmp.log", std::ios_base::app)); 

    // Tee filter instance (will be copied into each filter stream) 
    const bio::tee_filter<std::ostream> teeFilter(log); 

    // std::out tee 
    bio::filtering_ostream out; 
    out.push(teeFilter); 
    out.push(std::cout); 

    // std::in tee 
    bio::filtering_istream in; 
    in.push(teeFilter, 0); // If you don't pass 0 for buffer size, on std::cin it'll try to read 4096 chars and basically be useless 
    in.push(std::cin, 0); 

    out << "What is your name ?" << std::endl << std::flush; 
    std::string name; 
    getline(in, name); 
    out << "Hello " << name << std::endl << std::flush; 
}