2017-03-01 331 views
1

我想弄清楚用protobuf-net序列化的文件的最终大小,所以我可以选择最好的方法。如何计算protobuf文件大小?

我做了不同的原型配置和二进制序列化的比较测试,但我仍然不明白“varint to bytes”转换的工作原理。

public class Pt2D 
{ 
    public Pt2D() { } 

    public Pt2D(double x, double y) 
    { 
     X = x; 
     Y = y; 
    } 
    public double X { get; set; } 

    public double Y { get; set; } 
} 

public class Pt3D : Pt2D 
{ 
    public Pt3D() { } 

    public Pt3D(double x, double y, double z) : base(x, y) 
    { 
     Z = z; 
    } 
    public double Z { get; set; } 
} 

public class FullPt3D 
{ 
    public FullPt3D() { } 

    public FullPt3D(double x, double y, double z) 
    { 
     X = x; 
     Y = y; 
     Z = z; 
    } 

    public double X { get; set; } 

    public double Y { get; set; } 

    public double Z { get; set; } 
} 

测试用例

private void ProtoBufferTest() 
{    
    var model = RuntimeTypeModel.Default; 

    model.Add(typeof(Pt2D), false) 
     .Add(1, "X") 
     .Add(2, "Y") 
     .AddSubType(101, typeof(Pt3D)); 

    model[typeof(Pt3D)] 
     .Add(1, "Z"); 

    model.Add(typeof(FullPt3D), false) 
     .Add(1, "X") 
     .Add(2, "Y") 
     .Add(3, "Z"); 

    double x = 5.6050692524784562; 
    double y = 0.74161805247031987; 
    double z = 8.5883424750474937; 

    string filename = "testPt3D.pb"; 
    using (var file = File.Create(filename)) 
    { 
     Serializer.Serialize(file, new Pt3D(x, y, z));        
    } 
    Console.WriteLine(filename + " length = " + new FileInfo(filename).Length + " bytes") ; 

    filename = "testFullPt3D.pb"; 
    using (var file = File.Create(filename)) 
    { 
     Serializer.Serialize(file, new FullPt3D(x, y, z));     
    } 
    Console.WriteLine(filename + " length = " + new FileInfo(filename).Length + " bytes"); 

    filename = "testBinaryWriter.bin"; 
    using (var file = File.Create(filename)) 
    { 
     using (var writer = new BinaryWriter(file)) 
     {     
      writer.Write(x); 
      writer.Write(y); 
      writer.Write(z); 
     } 

    } 
    Console.WriteLine(filename + " length = " + new FileInfo(filename).Length + " bytes"); 


}  

测试结果

1)testPt3D.pb长度= 30个字节

2)testFullPt3D.pb长度= 27个字节

3)testBinaryWriter.bin长度= 24个字节

Q1) 24个字节被用于存储3个值和它的确定,但什么值被存储在例1)和2),以达到30首27个字节? (我想在模型映射中使用INT值)

Q2)我通过改变Pt2D亚型映射进行了一些测试,但我不理解的大小改变

model.Add(typeof(Pt2D), false) 
     .Add(1, "X") 
     .Add(2, "Y") 
     .AddSubType(3, typeof(Pt3D)); 

结果:testPt3D.pb长度= 29个字节

model.Add(typeof(Pt2D), false) 
     .Add(1, "X") 
     .Add(2, "Y") 
     .AddSubType(21, typeof(Pt3D)); 

结果:testPt3D.pb长度= 30个字节

model.Add(typeof(Pt2D), false) 
     .Add(1, "X") 
     .Add(2, "Y") 
     .AddSubType(1111, typeof(Pt3D)); 

结果:testPt3D.pb长度= 30字节

我试图用this tool来更好地理解,但它给出了不同的字节转换结果。

为什么使用21,101或1111可以获得相同的尺寸?

+0

还有这方面的线索吗? :( – ilCosmico

回答

1

1)testPt3D。pb长度= 30字节

  • (子类优先)[字段101,字符串] = 2字节,3位为“字符串”,7位为“101”; varint在7个为单位包有一个扩展位,从而:2个字节(总= 2)
    • [数据长度 “9”] = 1个字节(总共= 3)
    • [字段1,固定64] = 1个字节(总共= 4)
    • [有效载荷1] = 8个字节(总= 12)
  • [字段1,固定64] = 1个字节(总= 13)
  • [有效载荷1 ] = 8字节(总数= 21)
  • [字段2,固定64] = 1字节(总数= 22)
  • [有效载荷2] = 8个字节(总= 30)

2)testFullPt3D.pb长度= 27个字节

  • [字段1,固定64] = 1个字节(总= 1)
  • [有效载荷1] = 8个字节(总= 9)
  • [字段2,固定64] = 1个字节(总= 10)
  • [有效载荷2] = 8个字节(总= 18)
  • [字段3,固定64] = 1 b YTE(总= 19)
  • [净荷3] = 8个字节(总= 27)

反复数据处理时,有在protobuf的其他选项 - “打包” 和 “分组”;但只有在讨论更多数据时,它们才有意义。

+0

感谢您的解释,但我用来确定字段或子类的索引值不会影响大小?(请参阅我的最后一个问题 - 为什么使用21,101或1111获得相同的大小?) – ilCosmico

+0

@ ilCosmico字段编号以7位块打包**,但是第一个字节的** 3位已经被采用(对于线型) - 第一个块只有4位可用,所以你只能得到单字节标记为1-15(4比特);之后,使用下一个7比特的块,我们得到5-11比特的两个字节的标记(字段16-2047)。因此,由于所有你选择的数字是在16-2047范围内,它们全部需要2个字节,如果选择“3”则需要1个字节,如果选择“2500”则需要3个字节。 –

+0

再次感谢,现在更清楚:) – ilCosmico