2012-12-04 70 views
17

我需要一些指導或指導,瞭解如何實現自定義ostream。我的要求是:自定義ostream

  1. 以 '< <' 運營商A類幾種數據類型。
  2. 意圖是將輸出發送到數據庫。每條「線路」應該分別記錄。
  3. 每個記錄最重要的字段將是文本(或blob),但其他一些字段(如時間等)可以大部分自動推導出來
  4. 緩衝很重要,因爲我不想去數據庫每一條記錄。

首先,它是否值得從ostream中派生出來?我從ostream獲得什麼?如果我的課程簡單地實現了幾個方法(包括一些自定義數據類型),該怎麼辦?我從ostream獲得哪些功能?

假設我想要的是從ostream派生的類,我需要一些指導來理解ostream和streambuf類之間的關係。我需要執行哪一項?看一些示例,看起來我並不需要從ostream中派生出來,只需給ostream構造函數一個自定義的Streambuf即可。真的嗎?這是規範的方法嗎?

我需要實現自定義streambuf的哪些虛函數?我見過一些樣本(包括本網站:herehere,以及更多),有些覆蓋了sync方法,其他覆蓋了overflow方法。我應該重寫哪一個?另外,查看stringbuf和filebuf源文件(Visual Studio或GCC),這兩個緩衝區類都實現了streambuf的許多方法。

如果需要從streambuf派生的自定義類,那麼是否會從stringbuf(或任何其他類)派生出任何好處,而不是直接從streambuf派生?

至於「線條」。至少當我的使用'endl'操縱器的類的用戶成爲一個新行(即在數據庫中記錄)時。也許 - 取決於努力 - 每個'\ n'字符也應該被視爲新記錄。我的自定義ostream和/或streambuf會得到每個人的通知?

+2

您應該創建自己的'streambuf'類,它處理所有繁重的工作,然後創建一個非常簡單的'ostream'類,它繼承'std :: basic_ostream'並使用'streambuf'對象初始化自己。 –

+4

您應該查看[Boost.Iostreams](http://www.boost.org/doc/libs/release/libs/iostreams/doc/index.html) - 它使創建自定義流和緩衝區變得更簡單。 –

+0

感謝您的編輯,@MarkusParker – Uri

回答

15

ostream的自定義目標意味着實現您自己的ostreambuf。如果你想讓你的streambuf實際緩衝(即在每個字符之後不要連接到數據庫),最簡單的方法是創建一個繼承自std::stringbuf的類。 只有函數,你需要覆蓋的是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直到它被寫入。很棒!

+0

謝謝@JDW的編輯(必須手動重做)。 – Uri

+0

你的'MyStream'類是否繼承自'std :: ostream'?它是否覆蓋任何方法?我問這是因爲我得到一個錯誤,說明構造函數是受保護的 –

+0

我發現「清除緩衝區」的最佳方式是this-> str(「」)' – jtbr

18

最簡單的方法是繼承std::streambuf並重寫了兩個方法:

  • std::streamsize xsputn(const char_type* s, std::streamsize n) - 給定的緩衝區追加與提供給您的內部緩衝區,std::string例如大小;
  • int_type overflow(int_type c) - 將單個char附加到您的內部緩衝區。

您的streambuf可以根據需要構建(例如數據庫連接)。在將內容追加到內部緩衝區之後,您可以嘗試將其分割成多行並將某些內容推送到數據庫中(或者稍後緩衝一條SQL語句以稍後執行)。

要使用它:只需使用構造函數將您的streambuf附加到任何std::ostream

簡單!我已經做了這樣的事情來向syslog輸出字符串 - 對於用戶定義的類,任何自定義的operator<<都可以正常工作。

+2

不會實施xsputn打敗streambuf的全部目的? filebuf和stringbuf都不會覆蓋這個方法,但只會溢出(由stringbuf調用)。 – Uri

+0

實際上只有溢出方法纔會被覆蓋。默認情況下,sputn會對每個角色執行sputc。 – DawidPi

4

my2c - 我想你正在解決這個錯誤的方式。流可能聽起來像一個不錯的想法,但你也需要一種方法來指示行的結束(然後如果有人忘記了什麼?)我會建議一些java PreparedStatements和批處理的工作方式,如提供一組接受類型和列索引的方法,然後使用「批處理」方法明確說明您確實正在批處理該行,然後執行批處理。

任何基於流操作將依賴於類型(通常)來指示要填寫哪一列 - 但如果您有兩個整數?國際海事組織作爲用戶,它不覺得自然的方式插入記錄到數據庫...

1

要添加一個新的字符輸入/輸出到iostreams機制的來源或目的地,您應該創建一個新的streambuf班。流緩衝區類的任務是與將存儲字符的「外部設備」進行通信並提供緩衝設施。

使用iostream與數據庫通信的問題是數據庫表與字符序列的概念不匹配。有點像在一個方形的洞裏推一個圓形釘子。 A streambuf只能操作字符。這是提交給它的唯一一件事。這意味着streambuf必須解析呈現給它的字符流才能找到字段並記錄分隔符。 如果你決定走這條路線,我預測你最終會在你的streambuf中寫一個CSV到SQL的轉換器,只是爲了讓它工作。

您可能會更好,只需爲班級添加幾個operator<<重載。你可以在這裏看看Qt框架的想法。他們還可以使用operator<<將項目添加到集合等。

相關問題