我对打包字段以及存储/序列化有一些疑问 协议缓冲区的数据。 我本来想做的是将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会增加文件的大小而不是减少它。
任何提示都会非常感激!
感谢您的时间。
答案 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位来表示,效率会更高,如果大多数值都很小,效率会更低。