std :: ostream,为每一行调用一个回调

时间:2014-07-28 10:50:31

标签: c++ boost stl iostream boost-iostreams

我正在尝试编写一个自定义std::ostream,为写入它的每一行调用一个函数。也就是说,我希望以下代码能够按照注释中的说明进行操作:

my_output_stream s([] (const std::string& line) { 
    WriteLineToSomeOutput(line); 
});

s << "Hello world"; // do not invoke anything. The line has not ended yet!
s << ", from Alex" << std::endl; // here we invoke WriteLineToSomeOutput("hello world, from Alex")
s << "What's up"; // do not invoke anything. The line has not ended yet.
s << ", doc?!\nHow u doing?\n"; // Now we have two lines. We invoke WriteLineToSomeOutput("What's up, doc?!) and WriteLineToSomeOutput("How u doing?")

请注意,数据不会写入任何地方,也不会存储在任何地方。我需要存储流的唯一内容是正在聚合的当前行,直到我们遇到行尾。

即使使用boost.Iostreams库,我也没有找到任何简单的方法。我可以通过使用STL和Boost的一些内置工具来避免在这里编写我自己的行标记器吗?

背景

my_output_stream类将用于在我的应用程序中使用的外部库和日志库之间进行调整。外部库需要我提供了std :: ostream。我想使用我的应用程序的日志框架记录外部库记录的每一行。

3 个答案:

答案 0 :(得分:3)

如果我理解正确,你想无条件地冲洗 行尾,行尾。要做到这一点,你必须这样做 实施自己的streambuf;它可以基于 std::stringbuf,但如果您只关注输出, 并不担心寻求,它可能同样容易 它自己。

以下内容应该可以解决问题:

class LineBufferedOutput : public std::streambuf
{
    std::vector<char> myBuffer;
protected:
    int overflow( int ch ) override
    {
        myBuffer.push_back( ch );
        if ( ch == '\n' ) {
            //   whatever you have to do...
        }
        //  return traits::eof() for failure...
    }
};

我不确定你实现自己的标记器是什么意思; 没有涉及令牌化。你必须看看每一个 字符,以便将其与'\n'进行比较,但这就是全部。

您忽略了对sync()的任何明确请求。

答案 1 :(得分:0)

我可能首先实现一个可流设备,然后将其包装在boost :: iostream中。看一下boost :: iostreams并将其用作启动器:

#include <iosfwd>                           // streamsize, seekdir
#include <boost/iostreams/categories.hpp>   // seekable_device_tag
#include <boost/iostreams/positioning.hpp>  // stream_offset

#include <boost/function.hpp>

class MyDevice
{

  public:
    typedef boost::function<void()> Callback; // or whatever the signature should be
    typedef char                                   char_type;
    typedef boost::iostreams::seekable_device_tag  category;

    explicit MyDevice(Callback &callback);

    std::streamsize read(char* s, std::streamsize n);
    std::streamsize write(const char* s, std::streamsize n);
    std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way);

  private:
    MyDevice();
    Callback myCallback;
};

那将是基本宣言。您需要在.cpp文件中定义每个函数的实现方式。其中一个功能可能如下实现:

std::streampos MyDevice::write(const char* s, std::streamsize n)
{
    // process written data
    // file callback
    myCallback();
    // etc
}

然后从其他地方使用,例如在你的主要功能中:

Callback callback; // some function
MyDevice device(callback);
boost::iostreams::stream<MyDevice> stream(device);
stream << data; // etc.

答案 2 :(得分:0)

看起来你只是在寻找行缓冲,标准ostream已经这样做了(除非你明确要求它不要使用std::unitbufstd::flush操纵器)。

现在,长行可能会溢出输出缓冲区并触发“早期”刷新,但请记住,这可能会发生:如果输出到文件,操作系统将应用相同类型的缓冲策略,它不会你用什么方块冲洗长线真的很重要。

如果输出到套接字,例如那么你可以一次性发送缓冲区(如果你注意确保缓冲区足够大),但是TCP / IP层可以根据网络硬件的调整和限制自由地打破包中的流。< / p>