web-dev-qa-db-ja.com

Google Protocol Buffers-メッセージをファイルに保存する

株式市場データ(タイムスタンプ、入札、質問フィールドなど)をシリアル化するために、Googleプロトコルバッファーを使用しています。 1つのメッセージをファイルに保存し、問題なくデシリアライズできます。

複数のメッセージを単一のファイルに保存するにはどうすればよいですか?メッセージをどのように分離できるかわかりません。その場でファイルに新しいメッセージを追加できる必要があります。

36
DD.

MessageオブジェクトでwriteDelimitedTo(OutputStream)およびparseDelimitedFrom(InputStream)メソッドを使用することをお勧めします。 writeDelimitedToは、メッセージ自体の前にメッセージの長さを書き込みます。 parseDelimitedFromは、その長さを使用して1つのメッセージのみを読み取り、それ以上は読み取りません。これにより、複数のメッセージを単一のOutputStreamに書き込み、個別に解析できます。詳細については、 https://developers.google.com/protocol-buffers/docs/reference/Java/com/google/protobuf/MessageLite#writeDelimitedTo(Java.io.OutputStream) を参照してください。

30
Josh Hansen

ドキュメントから:

http://code.google.com/apis/protocolbuffers/docs/techniques.html#streaming

複数のメッセージのストリーミング

単一のファイルまたはストリームに複数のメッセージを書き込む場合、1つのメッセージが終了して次のメッセージが開始する場所を追跡するのはユーザー次第です。プロトコルバッファワイヤ形式は自己区切りではないため、プロトコルバッファパーサーはメッセージがどこで終了するかを判断できません。この問題を解決する最も簡単な方法は、メッセージ自体を書き込む前に各メッセージのサイズを書き込むことです。メッセージを読み戻すときは、サイズを読み取り、バイトを別のバッファーに読み取り、そのバッファーから解析します。 (バイトを別のバッファーにコピーしないようにするには、読み取りを特定のバイト数に制限するように指示できるCodedInputStreamクラス(C++とJavaの両方)をチェックしてください。)

13
DD.

Protobufには、最も外側のレコードごとにターミネーターが含まれていないため、それを自分で行う必要があります。最も簡単なアプローチは、データの前にレコードの長さを付けることです。個人的には、文字列ヘッダー(任意のフィールド番号)を記述し、次に「varint」として長さを書くというアプローチを使用する傾向があります。ただし、「繰り返し」要素を使用すると、固定長(通常は32ビットのリトルエンディアン)マーカーでも同様に機能します。このようなストレージでは、必要に応じて追加できます。

6
Marc Gravell

C++ソリューションを探している場合は、Kenton Varda 2015年8月頃にprotobufにパッチを提出 protoメッセージのシーケンスをシリアライズ/デシリアライズするwriteDelimitedTo()およびreadDelimitedFrom()呼び出しのサポートを追加します/ Javaこれらの呼び出しのバージョンと互換性のある方法でファイルから。残念ながら、このパッチはまだ承認されていないため、機能を自分でマージする必要がある場合。

もう1つのオプションは、Googleが他のプロジェクトを通じてコードを読み書きするオープンソースのprotobufファイルを持っていることです。たとえば、 または-tools ライブラリには、クラスへの RecordReader および RecordWriter が含まれています。これらは、ファイルへのプロトストリームをシリアル化/非シリアル化します。

外部依存関係がほとんどないこれらのクラスのスタンドアロンバージョンが必要な場合は、これらのクラスのみを含むor-toolsのフォークがあります。参照: https://github.com/moof2k/recordio

これらのクラスでの読み取りと書き込みは簡単です。

File* file = File::Open("proto.log", "w");
RecordWriter writer(file);
writer.WriteProtocolMessage(msg1);
writer.WriteProtocolMessage(msg2);
...
writer.Close();
5
moof2k