我在BinaryFormatter和Protobuf-net序列化器之间进行了一些比较,并且对我的 found感到非常高兴,但奇怪的是Protobuf-net可以将对象序列化成一个比我刚写的更小的字节数组每个属性的值都不包
我知道Protobuf-net如果将AsReference设置为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());
}
编辑:忘记添加,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; }
}
不,不是的;没有在原型规范中指定的“压缩”然而,它(默认情况下)使用“varint encoding” – 整数数据的可变长度编码,意味着小值使用较少的空间;所以0-127需要1个字节加上头。请注意,varint本身对于负数而言非常环绕,因此也支持“锯齿形”编码,允许小幅度数量较小(基本上,它交织正负对)。
实际上,在你的情况下,您还应该查看“打包”编码,它需要[ProtoMember(4,IsPacked = true)]或通过v2中的TypeModel等效(v2支持任一方法)。这样通过写入单个头和组合长度来避免每个值的头部开销。 “打包”可以用于varint / zigzag。还有一些固定长度的编码方案,你知道这些值可能很大而且不可预测。
另请注意:但是如果您的数据有很多文本,可以通过gzip或deflate另外运行,如果没有,那么gzip和deflate都可能导致它变大。
线格式is here的概述;了解并不是很棘手,可能会帮您计划如何进一步优化。
