我要将一些大对象存储到数据库(BLOB)中。正如我所见,protobuf是序列化/反序列化BLOB的最佳候选者之一。尽管它具有二进制格式,但仍然易于阅读和更改其内容(字符串,整数等)。所以我需要某种数据验证,无论何时它的原始 BLOB或修改过(黑客?太聪明的用户?)。
一种可能性是在表中有一个专用字段,称之为crc
,计算BLOB的校验和并将其放在那里。但是,当crc是BLOB本身的一部分时,它会好得多(在许多情况下)。
我可以在protobuf流的末尾添加额外的字节,但我必须删除它们(或者反序列化器会抛出异常"无效字段blablabla&# 34。)
我可以将protobuf流放入包装器中,但是打开/包装也是开销。
是否有一种简单且便宜的方法可以在protobuf流的末尾添加一些内容,以避免在反序列化过程中需要额外的操作?在XML中,我可以添加注释。我不认为protobuf中有注释,但是如何将CRC作为1或2个字节的例子?
答案 0 :(得分:5)
Protobuf流是可附加的。如果您知道数据中不存在的字段编号,则只需在该字段附加数据即可。如果您打算添加1或2个字节的CRC数据,那么“varint”可能是您最好的选择(注意“varint”是7位编码格式,第8位是延续标记,所以您可能想要使用7,14或21位或实际的CRC数据),然后你可以追加:
然而!这里的皱纹是解码器仍然经常解释和存储这些数据,这意味着如果你序列化它,它将把这些数据包含在输出中。
另一种避免这种情况的方法是在你自己设计的某些框架机制中封装 protobuf数据。例如,您可以选择:
我可能会选择第二种选择。请注意,如果需要,可以为长度前缀选择“varint”编码而不是固定长度编码。但是,对于CRC来说可能不值得,因为将固定长度。
答案 1 :(得分:2)
Crc应该在之前保存。这样就可以通过使用Seek
(跳过标题)从流中进行反序列化。
这是最简单的实现:
// serialize
using (var file = File.Create("test.bin"))
using (var mem = new MemoryStream())
{
Serializer.Serialize(mem, obj); // serialize obj into memory first
// ... calculate crc
file.Write(new byte[] { crc }, 0, 1);
mem.WriteTo(file);
}
// deserialize
using (var file = File.OpenRead("test.bin"))
{
var crc = file.ReadByte();
// ... calculate and check crc
file.Seek(1, SeekOrigin.Begin);
Serializer.Deserialize<ObjType>(file);
}