5

Protocol Buffers を使用してアプリケーション データを保存する Android アプリがあります。データ形式 (大まかに) は、protobuf (「アイテム」) のリストを繰り返しフィールドとして含む単一の protobuf (「コンテナー」) です。

message Container {
    repeated Item item = 1;
}

アイテムへの変更を保存する場合は、protobuf コンテナーを再作成し、すべてのアイテムを追加してから、シリアル化してファイルに書き込む必要があります。

このアプローチの問題は、保存時に使用されるメモリが 3 倍になる可能性があることです。これは、データを最初にモデル クラスから protobuf ビルダーにコピーし、次に protobuf をシリアル化するときにバイト配列にコピーする必要があるためです。ファイルストリーム。

私たちが望むのは、protobuf コンテナーを作成し、それを遅延してストリームにシリアル化してから、(モデル データから作成された) 各 protobuf アイテムをコンテナーに追加するだけで、シリアル化してストリームに書き込む方法です。メモリ内にコンテナ全体を作成するまで、メモリ内のアイテム。

protobuf を作成し、遅延してストリームにシリアル化する方法はありますか?

これを公式に行う方法がない場合、役立つライブラリはありますか? これを他の方法で解決するための提案やアイデアはありますか? これを可能にする代替データ形式またはテクノロジー (protobufs を含む JSON または XML など) はありますか?

4

3 に答える 3

5

シリアル化の場合:

protobuf は追加可能な形式で、個々のアイテムがマージされ、繰り返されるアイテムが追加されます

したがって、シーケンスをレイジー ストリームとして記述するには、リスト内の項目が 1 つだけの同じ構造を繰り返し記述するだけで済みます。 「200アイテム入りコンテナ」。

だから:それをしてください!


逆シリアル化の場合:

これは技術的にはストリームとして読むのは非常に簡単ですが、すべては使用しているライブラリに依存します。たとえば、これを protobuf-net (.NET / C# 実装) として として公開します。これは、質問で説明した形式であるという仮定に基づいて、Serializer.DeserializeItems<T>タイプ のメッセージのシーケンスを (完全に遅延/ストリーミング) 読み取ります。 T(これSerializer.DeserializeItems<Item>は、ストリーミングの方法で置き換えられますSerializer.Deserialize<Container>-最も外側のオブジェクトは、protobufには実際には存在しません)

これが利用できないが、生のリーダー API にアクセスできる場合は、次のことを行う必要があります。

  • ヘッダーの varint を 1 つ読み取ります。これは値 10 (0x0A) になります。つまり、フィールド番号 (1) とワイヤ タイプ (2) はそれぞれ「(1 << 3) | 2」です。言い回し: 「ストリームから 1 バイトを読み取り、値が 10 であることを確認する」
  • 次の項目の長さに対して 1 つの varint を読み取ります
  • 今:
    • リーダー API で処理する最大バイト数を制限できる場合は、この長さを使用して、次の長さを指定します。
    • または、その長さに制限された長さ制限ストリームでストリーム API をラップします。
    • または、そのバイト数を手動で読み取り、ペイロードからメモリ内ストリームを構築します
  • すすぎ、繰り返す
于 2012-11-06T13:14:09.077 に答える
0

プロトコル バッファの通常の Java バージョンには、一度に 1 つずつプロトコル バッファを書き込む区切りファイルがあります。Android版かどうかはわかりません

 aLocation.writeDelimitedTo(out);

マークが示したように、簡単に実装できます。シリアル化されたバイトの後に長さを書き込むだけです。通常の (Android 以外の) Java バージョンの prortocol-buffers でも実行できます (バイト配列などにシリアル化する必要があります)。

private CodedOutputStream codedStream = null;


public void write(byte[] bytes) throws IOException {
    if (bytes != ConstClass.EMPTY_BYTE_ARRAY) {
        codedStream.writeRawVarint32(bytes.length);
        codedStream.writeRawBytes(bytes);
        codedStream.flush();
    }
}

    private CodedInputStream coded;

public byte[] read() throws IOException {
    if (coded == null) {
        throw new IOException("Reader has not been opened !!!");
    }
    if (coded.isAtEnd()) {
        return null;
    }
    return coded.readBytes().toByteArray();

他の Protocol-Buffers バージョンでは何かが可能かもしれません

于 2012-11-07T21:38:12.687 に答える
0

そのようなことはない。protobuf はパック構造です。これを効果的に行うには、すべてのデータが必要です。「ストリーミング プロトコル」を自分で追加する必要があります。おそらく、N 個のアイテムごとに protobuf メッセージを送信します。

于 2012-11-05T23:57:06.483 に答える