27

カスタム ostream の実装方法を理解するためのガイダンスまたは指針が必要です。私の要件は次のとおりです。

  1. 複数のデータ型の「<<」演算子を持つクラス。
  2. 意図は、出力をデータベースに送信することです。各「行」は個別のレコードに移動する必要があります。
  3. 各レコードの最も重要なフィールドはテキスト (またはブロブ) ですが、時間などの他のフィールドはほとんど自動的に推測できます。
  4. レコードごとにデータベースにアクセスしたくないので、バッファリングは重要です。

まず、ostream から派生させる価値はありますか? ostream から派生すると何が得られますか? 私のクラスがいくつかoperator<<のメソッド (いくつかのカスタム データ型を含む) を実装するだけの場合はどうなるでしょうか。ostream から得られる機能はどれですか?

私が望むのは ostream から派生したクラスであると仮定すると、ostream クラスと streambuf クラスの関係を理解するためのガイダンスが必要です。どちらを実装する必要がありますか? いくつかのサンプルを見ると、ostream から派生させる必要はまったくなく、ostream コンストラクターにカスタム streambuf を与えるだけであることがわかります。本当?それは標準的なアプローチですか?

カスタム streambuf のどの仮想関数を実装する必要がありますか? いくつかのサンプル (このサイト: herehere 、およびその他のいくつかを含む) を見てきました。メソッドをオーバーライドするものもあれば、syncメソッドをオーバーライドするものもありますoverflow。どちらをオーバーライドする必要がありますか? また、stringbuf と filebuf のソース (Visual Studio または GCC) を見ると、これらのバッファ クラスは両方とも streambuf の多くのメソッドを実装しています。

streambuf から派生したカスタム クラスが必要な場合、streambuf から直接ではなく、stringbuf (または他のクラス) から派生する利点はありますか?

「線」について。少なくとも「endl」マニピュレータを使用するクラスのユーザーが新しい行になるようにしたいと思います(つまり、データベースに記録します)。おそらく - 努力次第です - すべての '\n' 文字も新しいレコードと見なす必要があります。カスタム ostream および/または streambuf はそれぞれ誰に通知されますか?

4

4 に答える 4

30

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 が書き込まれるまで保存する があります。よく働く!

于 2013-01-09T10:03:59.837 に答える
23

最も簡単な方法は、次の 2 つのメソッドだけを継承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<<が、ユーザー定義クラスのカスタムで正常に動作します。

于 2012-12-04T13:32:20.233 に答える
4

my2c - あなたはこれに間違った方法で取り組んでいると思います。ストリームはいいアイデアのように聞こえるかもしれませんが、行の終わりを示す方法も必要になります (そして、誰かが忘れた場合はどうすればよいでしょうか?) Java PreparedStatements とバッチがどのように機能するかという行に沿って何かを提案します。タイプと列インデックスを受け入れる一連のメソッドを提供し、次に、実際にその行をバッチ処理していることを明示的に明らかにする「バッチ」メソッドを提供し、次にバッチをプッシュする実行を行います。

ストリームベースの操作は、(通常) タイプに依存して、入力する列を示しますが、2 つの int がある場合はどうなるでしょうか? IMO、ユーザーとして、レコードをデータベースに挿入する自然な方法のようには感じません...

于 2012-12-04T13:56:01.610 に答える
1

文字入出力の新しいソースまたは宛先を iostreams メカニズムに追加するには、新しいstreambufクラスを作成する必要があります。ストリーム バッファ クラスのタスクは、文字を格納する「外部デバイス」と通信し、バッファリング機能を提供することです。

iostream を使用してデータベースと通信する際の問題は、データベース テーブルが文字シーケンスの概念と一致しないことです。四角い穴に丸いペグを押し込むようなものです。Astreambufは文字のみを操作します。それがこれまでに提示された唯一のものです。これはstreambuf、フィールドとレコードの区切りを見つけるために、提示された文字ストリームを解析する必要があることを意味します。このルートに進むことにした場合、CSV から SQL へのコンバーターを .csv ファイルに書き込んで動作させることになると思いますstreambuf

operator<<クラスにいくつかのオーバーロードを追加するだけで、おそらくより良くなるでしょう。ここでアイデアのQtフレームワークを見ることができます。operator<<コレクションなどにアイテムを追加するために使用する可能性もあります。

于 2012-12-04T14:29:01.850 に答える