编码,数据类型和包装重复的字段

时间:2012-02-06 13:16:16

标签: c++ serialization protocol-buffers

我对打包字段以及存储/序列化有一些疑问 协议缓冲区的数据。 我本来想做的是将4MB的数据存储到文件中。

我(在我们的嵌入式系统中)的数据是作为uint8_t(一个字节)接收的,我想尽可能有效地存储这些数据。

我一直在测试各种protobuf设置(四个);

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

将两个变量分配为1对1(将uint8放入uint32),并将两个变量bithifted与4个值限制在uint32_t中。

令我惊讶的是,存储的文件比原始文件大得多 数据。 (当然,我将uint8放入uint32的示例当然是..) 对于4MB数据,我可以达到的最佳结果是5.2MB 真的不是那么好。

我误解了一些重要的东西吗? 我确实意识到protobuf会为数据包添加信息,但是25% 增加太多了。

同样使用GzipOutputStream会增加文件的大小而不是减少它。

任何提示都会非常感激!

感谢您的时间。

2 个答案:

答案 0 :(得分:2)

此答案基于您在.proto术语中使用uint32的假设:

packed在这里是一件好事(每个值删除标头);但是,通过将单个uint8打包到uint32中,您将遇到“varint”编码的一个方面 - 具体而言,如果设置了该字节的最高位,则需要2个字节(varint每个字节使用7位数据,以及 continuation 的一位。因此,我建议切换到bytes类型,它代表任意字节块,并按“原样”编码,没有任何varint或类似。它不会重复/打包 - 只是:

[required|optional] bytes data = 1;

另一种选择是使用fixed32(重复和打包),并且每个值放置(通过移位)4个字节,但是当你完成时,你也可以转到{{1}并且有一个更明显的1:1地图。

Re gzip; gzip在没有很多重复块的情况下增加任意二进制文件的大小并不罕见。相比之下,如果您的protobuf文档包含字符串,则缩小大小是很常见的,因为gzip可以发现重复的块。

答案 1 :(得分:1)

如果要存储字节序列,请使用bytes数据类型。开销很小。

您从int32看到的额外开销来自可变长度编码;数字在每个字节中以7位存储,第8位表示是否有更多。因此,满量程32位值将需要5个字节来存储。有一个fixed32类型,每个值总是需要32位(4个字节) - 如果大多数值需要32位来表示,效率会更高,如果大多数值都很小,效率会更低。