2012-02-06 13 views
1

パックフィールドに関する質問があり、データをプロトコルバッファで保存/シリアル化しています。 私が本質的にやりたいことは、4MBのデータをファイルに保存することです。エンコーディング、データ型、およびパックされた繰り返しフィールド

私は(私たちの組み込みシステムで)持っているデータはuint8_t(1バイト)として受け取りました。私はできるだけ効率的にこのデータを保存したいと思います。

私はさまざまなprotobuf設定(4つ)をテストしています。

repeated uint32_t datastruct = 1; 
repeated uint32_t datastruct = 1 [packed = true] 

両方の変異体が(UINT32にUINT8を置く)1対1に割り当てられ、4つの値でbitshifted両方の変異体がのuint32_tに窮屈で。

私の驚いたことに、格納されたファイルは元の データよりもはるかに大きいです。 (私がuint32にuint8を入れた例は当然期待されていました..) 私が達成できる最良の結果は、4MBのデータでは5.2MBでしたが、 はそれほど良いものではありません。

私はここで重要なことを誤解しましたか? 私はprotobufがパケットに情報を追加することを認識しますが、25% の増加が大きすぎます。

また、GzipOutputStreamを使用すると、ファイルを小さくする代わりにサイズを大きくします。

ヒントをお聞かせください。

お時間をいただきありがとうございます。

+0

ここでは 'uint32_t'とは何ですか?それは.protoの 'message'ですか? –

+0

はい、そうです。 – almagest

+0

それから...私は混乱しています...私はそのようなことをしても "詰まった"とは思っていませんでした...?それともグループですか? –

答えて

2

この答えは、あなたが.proto用語でuint32を使用しているという仮定に基づいています。

packedはここに肯定的なものである(値ごとにヘッダを削除します)。しかし、単一のuint8をuint32にパックすると、 "varint"エンコーディングのファセットに入ります。特に、バイトの最上位ビットが設定されている場合、2バイトがかかります(varintは1バイトあたり7ビットを使用します)。データ、そして1ビットは継続)。したがって、任意のチャンクのバイトを表すbytesタイプに切り替えることをお勧めします。これは、varintなどは一切使わずに "そのまま"エンコードされます。別のオプションは、値ごとに4バイトfixed32(繰り返し、パック)、および(シフト経由)の場所を使用することです

[required|optional] bytes data = 1; 

が、時間によって、あなたがやった:ちょうど - パック/繰り返されることはありませんあなたはbytesに行き、より明白な1:1マップを持っているかもしれません。

Re gzip; gzipが多くの繰り返しブロックなしで任意のバイナリのサイズを増やすことは珍しいことではありません。これとは対照的に、protobufドキュメントに文字列が含まれている場合、gzipは繰り返しブロックを見つけることができるため、サイズを縮小するのが一般的です。

+0

データ用に7ビット、継続用に1ビット。 –

+0

@wood_brian oops! typo –

+0

bytesデータ型を使用してテストすると、消費される領域は着信データよりわずかに多くなりました。パターンがデータに出現すると、protobufメッセージで消費された領域が大幅に減少しました。 – almagest

1

バイトのシーケンスを格納する場合は、bytesデータ型を使用します。オーバーヘッドはごくわずかです。

int32から表示される余分なオーバーヘッドは、可変長コーディングに由来します。数字は各バイトに7ビットで格納され、8番目にはそれ以上が存在するかどうかが示されます。したがって、フルスケールの32ビット値は5バイトを格納する必要があります。fixed32タイプがあり、値ごとに常に32ビット(4バイト)がかかります。ほとんどの値が32ビットで表現する必要がある場合はより効率的です。ほとんどの値が小さい場合は効率が低下します。

+0

、具体的には、オーバーヘッド(図示のフィールド#1)はヘッダーに1バイト、 4MBの長さを表すバイトを "varint" –

関連する問題