我正在尝试编写一个自定义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。我想使用我的应用程序的日志框架记录外部库记录的每一行。
答案 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::unitbuf
或std::flush
操纵器)。
现在,长行可能会溢出输出缓冲区并触发“早期”刷新,但请记住,这可能会发生:如果输出到文件,操作系统将应用相同类型的缓冲策略,它不会你用什么方块冲洗长线真的很重要。
如果输出到套接字,例如那么你可以一次性发送缓冲区(如果你注意确保缓冲区足够大),但是TCP / IP层可以根据网络硬件的调整和限制自由地打破包中的流。< / p>