Protobuf-net是否具有用于序列化的内置压缩?

the*_*onk 25 serialization protobuf-net binary-serialization

我正在BinaryFormatter和Protobuf-net序列化器进行一些比较,并对我发现的内容非常满意,但奇怪的是,Protobuf-net设法将对象序列化为比我刚写入值时更小的字节数组.将每个属性转换为没有任何元数据的字节数组.

我知道如果设置AsReference为Protobuf-net支持字符串实习true,但在这种情况下我不是这样做的,那么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());
}
Run Code Online (Sandbox Code Playgroud)

编辑:忘了添加,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; }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 32

不,不是的; protobuf规范中没有指定"压缩"; 但是,它(默认情况下)使用"varint encoding" - 整数数据的可变长度编码,这意味着小值使用更少的空间; 所以0-127需要1个字节加上标题.注意,对于负数,varint 本身变得非常循环,因此也支持"zigzag"编码,这允许小幅度数量很小(基本上,它交错正负对).

实际上,在你的情况下,Scores你也应该看看"打包"编码,它需要或者在v2中[ProtoMember(4, IsPacked = true)]使用等效的via TypeModel(v2支持这两种方法).通过编写单个标头和组合长度,这可以避免每个标头的开销."Packed"可以与varint/zigzag一起使用.对于您知道值可能很大且不可预测的情况,还有固定长度编码.

另请注意:但如果您的数据有大量文本,您可以通过gzip或deflate额外运行它来获益; 如果没有,那么gzip和deflate都会导致它变大.

这里是有线格式的概述; 理解并不是很棘手,可能会帮助您规划如何进一步优化.

  • @tobi它对字段编号使用"varint"编码 - 这意味着7位有效载荷,1位"还有另一个要读取的字节".你继续阅读,直到MSB为零. (8认同)