2011-08-24 89 views
18

我在BinaryFormatter和Protobuf-net串行器之间进行了一些比较,并且对我的found很满意,但奇怪的是Protobuf-net设法将对象序列化为比我得到的更小的字节数组将每个属性的值写入没有任何元数据的字节数组中。Protobuf-net是否具有用于序列化的内置压缩?

我知道Protobuf-net支持字符串实习,如果你设置AsReferencetrue,但我没有这样做,那么Protobuf-net默认提供了一些压缩?

下面是一些代码可以运行自己看看:

var simpleObject = new SimpleObject 
         { 
          Id = 10, 
          Name = "Yan", 
          Address = "Planet Earth", 
          Scores = Enumerable.Range(1, 10).ToList() 
         }; 

using (var memStream = new MemoryStream()) 
{ 
    var binaryWriter = new BinaryWriter(memStream); 
    // 4 bytes for int 
    binaryWriter.Write(simpleObject.Id);  
    // 3 bytes + 1 more for string termination 
    binaryWriter.Write(simpleObject.Name);  
    // 12 bytes + 1 more for string termination 
    binaryWriter.Write(simpleObject.Address); 
    // 40 bytes for 10 ints 
    simpleObject.Scores.ForEach(binaryWriter.Write); 

    // 61 bytes, which is what I expect 
    Console.WriteLine("BinaryWriter wrote [{0}] bytes", 
     memStream.ToArray().Count()); 
} 

using (var memStream = new MemoryStream()) 
{ 
    ProtoBuf.Serializer.Serialize(memStream, simpleObject); 

    // 41 bytes! 
    Console.WriteLine("Protobuf serialize wrote [{0}] bytes", 
     memStream.ToArray().Count()); 
} 

编辑:忘了补充,该SimpleObject类看起来是这样的:

[Serializable] 
[DataContract] 
public class SimpleObject 
{ 
    [DataMember(Order = 1)] 
    public int Id { get; set; } 

    [DataMember(Order = 2)] 
    public string Name { get; set; } 

    [DataMember(Order = 3)] 
    public string Address { get; set; } 

    [DataMember(Order = 4)] 
    public List<int> Scores { get; set; } 
} 

回答

26

不,它不需要;在protobuf规范中没有规定的“压缩”;然而,它确实(默认情况下)使用“varint编码” - 整数数据的可变长度编码,这意味着小值使用更少的空间;所以0-127需要1个字节加头。需要注意的是varint 本身变为负数很糊涂,所以“曲折”编码也支持,允许小幅度数字要小(基本上,它交织正面和负面的对)。

实际上,在你的情况下,你应该看看“packed”编码,它需要[ProtoMember(4, IsPacked = true)]或通过在V2中的等效(V2支持这两种方法)。这避免了每个值的头部开销,通过写入单个头部和长度的组合。 “Packed”可以与varint/zigzag一起使用。对于您知道的值可能很大且不可预测的场景,也有定长编码。

另请注意:但是如果您的数据中有很多文本,您可能会通过gzip或deflate另外运行它;如果它不是,那么gzip和deflate都可能导致它变大。

电线格式概述is here;理解起来并不是非常棘手,并且可以帮助您规划如何进一步优化。

+0

谢谢,这一切都有道理吧! – theburningmonk

+0

为什么protobuf仅为128个值创建1个字节? 8位允许写入256个不同的值。 – tobi

+6

@tobi它使用“varint”编码字段编号 - 这意味着7位有效负载,1位“有另一个字节要读取”。你继续阅读直到MSB为零。 –

相关问题