我需要一些指导或指导,了解如何实现自定义ostream。我的要求是:
首先,是否值得从ostream中获取?从ostream得到什么?如果我的类只实现了少量operator<<
方法(包括一些自定义数据类型),该怎么办?我从ostream获得哪些功能?
假设我想要的是一个源自ostream的类,我需要一些指导来理解ostream和streambuf类之间的关系。我需要实施哪一个?看一些样本,似乎我根本不需要从ostream派生,只需给ostream构造函数一个自定义的streambuf。真的吗?这是规范的方法吗?
我需要在自定义streambuf中实现哪些虚拟功能?我看过一些示例(包括此网站:here和here,还有更多),有些会覆盖sync
方法,而其他方法会覆盖overflow
方法。我应该覆盖哪一个?另外,查看stringbuf和filebuf源(Visual Studio或GCC),这两个缓冲类都实现了streambuf的许多方法。
如果需要从streambuf派生的自定义类,是否可以从stringbuf(或任何其他类)而不是直接从streambuf获得任何好处?
至于“线”。至少当我使用'endl'操纵器的类的用户是一个新行(即数据库中的记录)时,我想。也许 - 取决于努力 - 每个'\ n'字符也应被视为新记录。谁为我的自定义ostream和/或streambuf获得通知?
答案 0 :(得分:20)
ostream的自定义目标意味着实现您自己的ostreambuf。如果您希望streambuf实际缓冲(即在每个字符后不连接到数据库),最简单的方法是创建一个继承自std::stringbuf
的类。您需要覆盖的 only 函数是sync()
方法,只要刷新流就会调用该方法。
class MyBuf : public std::stringbuf
{
public:
virtual int sync() {
// add this->str() to database here
// (optionally clear buffer afterwards)
}
};
然后,您可以使用缓冲区创建std::ostream
:
MyBuf buff;
std::ostream stream(&buf)
大多数人建议不要将流重定向到数据库,但是他们忽略了我的描述,即数据库基本上只有一个blob字段,所有文本都将在其中。 在极少数情况下,我可能会将数据发送到其他字段。这可以通过我的流理解的自定义属性来促进。例如:
MyStream << "Some text " << process_id(1234) << "more text" << std::flush
上面的代码将在数据库中创建一条记录:
blob: 'Some text more text'
process_id: 1234
process_id()
是一个返回结构ProcessID
的方法。然后,在我的ostream的实现中,我有一个operator<<(ProcessID const& pid)
,它存储进程ID直到它被写入。效果很棒!
答案 1 :(得分:17)
最简单的方法是继承std::streambuf
并仅覆盖两种方法:
std::streamsize xsputn(const char_type* s, std::streamsize n)
- 附加一个提供给内部缓冲区的给定缓冲区,例如std::string
; int_type overflow(int_type c)
- 将单个char
附加到内部缓冲区。您的streambuf可以根据您的需要构建(例如DB连接)。在将内容添加到内部缓冲区后,您可以尝试将其拆分为行并将某些内容推送到DB中(或者只是缓冲SQL语句以便稍后执行)。
要使用它:只需使用构造函数将streambuf
附加到任何std::ostream
。
简单!我已经做了类似的事情来将字符串输出到syslog - 对于用户定义的类,任何自定义operator<<
都能正常工作。
答案 2 :(得分:4)
my2c - 我认为你是以错误的方式解决这个问题。一个流听起来可能是一个好主意,但你需要一种方法来指示行的结尾(然后如果有人忘了怎么办?)我会建议一些关于java PreparedStatements和批处理如何工作的内容,如提供一组接受类型和列索引的方法,然后是一个“批处理”方法,它明确表明您确实正在批处理该行,然后执行以推送批处理。
任何基于流的操作都将依赖于类型(通常)来指示要填充的列 - 但如果您有两个整数,该怎么办? IMO,作为用户,它不像是将记录插入数据库的自然方式......
答案 3 :(得分:1)
要将字符输入/输出的新源或目标添加到iostreams机制,您应该创建一个新的streambuf
类。流缓冲类的任务是与将存储字符的“外部设备”进行通信,并提供缓冲设施。
使用iostream与数据库通信的问题是数据库表与字符序列的概念不匹配。有点像在一个方孔中推一个圆钉。 streambuf
仅对字符进行操作。这是唯一呈现给它的东西。这意味着streambuf
必须解析呈现给它的字符流以查找字段和记录分隔符。
如果您决定采用这种方式,我预测您最终会在streambuf
中编写一个CSV-to-SQL转换器,以使其正常工作。
如果只为您的类添加一些operator<<
重载,您可能会更好。你可以在这里查看Qt框架的想法。他们还可以使用operator<<
向集合中添加项目等。