我有一些关于打包字段和存储/序列化的问题 带有 Protocol Buffer 的数据。 我基本上想做的是将 4MB 的数据存储到一个文件中。
我拥有的数据(在我们的嵌入式系统中)以 uint8_t(一个字节)的形式接收,我想尽可能高效地存储这些数据。
我一直在测试各种 protobuf 设置(四种);
repeated uint32_t datastruct = 1;
repeated uint32_t datastruct = 1 [packed = true]
两个变体都被一对一分配(将 uint8 赋值给 uint32),并且两个变体都用 4 个值移位到一个 uint32_t 中。
令我惊讶的是,存储的文件比原始文件大得多 数据。 (当然,我将 uint8 放入 uint32 的示例是预期的......) 对于 4MB 数据,我能达到的最好结果是 5.2MB,这 真的不是那么好。
我是不是误解了一些重要的东西? 我确实意识到 protobuf 向数据包添加了信息,但是 25% 恕我直言,增加太多了。
同样使用 GzipOutputStream 会增加文件的大小而不是减少它。
如有任何提示,我们将不胜感激!
感谢您的宝贵时间。
最佳答案
这个答案是基于你在 .proto 术语中使用 uint32
的假设:
packed
在这里是一件好事(删除每个值的 header );但是,通过将单个 uint8 打包到 uint32 中,您将遇到“varint”编码的一个方面——具体来说,如果设置了字节的最高有效位,它将占用 2 个字节(varint 每个字节使用 7 位数据,一位作为 continuation)。因此,我建议切换到 bytes
类型,它代表任意字节 block ,并且“按原样”编码,没有任何 varint 或类似的。它不会被重复/打包 - 只是:
[required|optional] bytes data = 1;
另一种选择是使用 fixed32
(重复和压缩),并为每个值放置(通过移位)4 个字节,但是当您完成后,您也可以转到 bytes
有更明显的1:1映射。
重新压缩; gzip 在没有许多重复 block 的情况下增加任意二进制文件的大小并不少见。相比之下,如果您的 protobuf 文档包含字符串,则大小通常会缩小,因为 gzip 可以发现重复的 block 。
关于c++ - 编码、数据类型和打包的重复字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9160646/