zoukankan      html  css  js  c++  java
  • protobuf-net-data

    protobuf-net

    http://www.codeproject.com/Articles/642677/Protobuf-net-the-unofficial-manual

    https://github.com/rdingwall/protobuf-net-data

    https://github.com/mgravell/protobuf-net

    protobuf是google的一个开源项目,可用于以下两种用途:

      (1)数据的存储(序列化和反序列化),类似于xml、json等;

      (2)制作网络通信协议。

      源代码下载地址:https://github.com/mgravell/protobuf-net

      开源项目地址如下:https://code.google.com/p/protobuf-net/,下载解压后的目录如下所示,每个文件夹的详细介绍都在最后一个txt文件里面了。

      

      ProtoGen是用来根据***.proto文件生成对应的***.cs文件的,而做数据存储功能只需要用到protobuf-net.dll即可,至于使用哪个版本项目情况决定。下面的例子在Windows平台下新建一个C#的控制台工程,并引入ProtoBufNetFull et30protobuf-net.dll,代码如下所示:

    复制代码
    namespace TestProtoBuf
    {
        [ProtoContract]
        public class Address
        {
            [ProtoMember(1)]
            public string Line1;
            [ProtoMember(2)]
            public string Line2;
        }
    
        [ProtoContract]
        public class Person
        {
            [ProtoMember(1)]
            public int Id;
            [ProtoMember(2)]
            public string Name;
            [ProtoMember(3)]
            public Address Addr;
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Person person = new Person();
                person.Id = 1;
                person.Name = "First";
                person.Addr = new Address { Line1="line1", Line2="line2"};
    
                // ProtoBuf序列化
                using(var file = System.IO.File.Create("Person.bin"))
                {
                    ProtoBuf.Serializer.Serialize(file, person);
                }
    
                // ProtoBuf反序列化
                Person binPerson = null;
                using(var file = System.IO.File.OpenRead("Person.bin"))
                {
                    binPerson = ProtoBuf.Serializer.Deserialize<Person>(file);
                }
    
                System.Console.WriteLine(binPerson.Name);
            }
        }
    }
    复制代码

      可以看到序列化和反序列化的代码非常简单。

      protobuf提供了一种proto脚本用来编写***.proto文件,这种脚本格式简单、可读性强、方便扩展,用proto脚本定义网络协议是非常好用的。

      下面是一个proto脚本的简单例子:

    复制代码
    message Person {
        required string name=1;
        required int32 id=2;
        optional string email=3;
    
        enum PhoneType {
            MOBILE=0;
            HOME=1;
            WORK=2;
        }
    
        message PhoneNumber {
            required string number=1;
            optional PhoneType type=2 [default=HOME];
        }
    
        repeated PhoneNumber phone=4;
    }
    复制代码

      requied是必须有的字段、optional是可有可无的字段、repeated是可以重复的字段(数组或列表),同时枚举字段都必须给出默认值。

      接下来就可以使用ProgoGen来根据proto脚本生成源代码cs文件了,命令行如下:

      protogen -i:test.proto -0:test.cs -ns:MyProtoBuf

      -i指定了输入,-o指定了输出,-ns指定了生成代码的namespace,上面的proto脚本生成的源码如下:

    复制代码
    //------------------------------------------------------------------------------
    // <auto-generated>
    //     This code was generated by a tool.
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    // Generated from: file/pb.proto
    namespace MyProtoBuf
    {
      [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"Person")]
      public partial class Person : global::ProtoBuf.IExtensible
      {
        public Person() {}
        
        private string _name;
        [global::ProtoBuf.ProtoMember(1, IsRequired = true, Name=@"name", DataFormat = global::ProtoBuf.DataFormat.Default)]
        public string name
        {
          get { return _name; }
          set { _name = value; }
        }
        private int _id;
        [global::ProtoBuf.ProtoMember(2, IsRequired = true, Name=@"id", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
        public int id
        {
          get { return _id; }
          set { _id = value; }
        }
        private string _email = "";
        [global::ProtoBuf.ProtoMember(3, IsRequired = false, Name=@"email", DataFormat = global::ProtoBuf.DataFormat.Default)]
        [global::System.ComponentModel.DefaultValue("")]
        public string email
        {
          get { return _email; }
          set { _email = value; }
        }
        private readonly global::System.Collections.Generic.List<Person.PhoneNumber> _phone = new global::System.Collections.Generic.List<Person.PhoneNumber>();
        [global::ProtoBuf.ProtoMember(4, Name=@"phone", DataFormat = global::ProtoBuf.DataFormat.Default)]
        public global::System.Collections.Generic.List<Person.PhoneNumber> phone
        {
          get { return _phone; }
        }
      
      [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"PhoneNumber")]
      public partial class PhoneNumber : global::ProtoBuf.IExtensible
      {
        public PhoneNumber() {}
        
        private string _number;
        [global::ProtoBuf.ProtoMember(1, IsRequired = true, Name=@"number", DataFormat = global::ProtoBuf.DataFormat.Default)]
        public string number
        {
          get { return _number; }
          set { _number = value; }
        }
        private Person.PhoneType _type = Person.PhoneType.HOME;
        [global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=@"type", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
        [global::System.ComponentModel.DefaultValue(Person.PhoneType.HOME)]
        public Person.PhoneType type
        {
          get { return _type; }
          set { _type = value; }
        }
        private global::ProtoBuf.IExtension extensionObject;
        global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
          { return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
      }
      
        [global::ProtoBuf.ProtoContract(Name=@"PhoneType")]
        public enum PhoneType
        {
                
          [global::ProtoBuf.ProtoEnum(Name=@"MOBILE", Value=0)]
          MOBILE = 0,
                
          [global::ProtoBuf.ProtoEnum(Name=@"HOME", Value=1)]
          HOME = 1,
                
          [global::ProtoBuf.ProtoEnum(Name=@"WORK", Value=2)]
          WORK = 2
        }
      
        private global::ProtoBuf.IExtension extensionObject;
        global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
          { return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
      }
      
    }
    复制代码

      to be continue...

     

    什么是ProtoBuf-net

    Protobuf是google开源的一个项目,用户数据序列化反序列化,google声称google的数据通信都是用该序列化方法。它比xml格式要少的多,甚至比二进制数据格式也小的多。

    Protobuf格式协议和xml一样具有平台独立性,可以在不同平台间通信,通信所需资源很少,并可以扩展,可以旧的协议上添加新数据

    Protobuf是在java和c++运行的,Protobuf-net当然就是Protobuf在.net环境下的移植。

    请参见:https://code.google.com/p/protobuf-net/ 

    Get Start

    [ProtoBuf.ProtoContract]
        public class Person
        {
            [ProtoBuf.ProtoMember(1)]
            public int Id { get; set; }
            [ProtoBuf.ProtoMember(2)]
            public string Name { get; set; }
            [ProtoBuf.ProtoMember(3)]
            public Address Address { get; set; }
        }
    
        [ProtoBuf.ProtoContract]
        public class Address
        {
            [ProtoBuf.ProtoMember(1)]
            public string Line1 { get; set; }
            [ProtoBuf.ProtoMember(2)]
            public string Line2 { get; set; }
        }

    类前加上ProtoContract Attrbuit,成员加上ProtoMember Attribute即可,其中ProtoMember需要一个大于0的int类型的值,原则上这个int类型没有大小限制,但建议从1开始,这是一个良好的习惯,另外这个参数必需是这个类成员的唯一标识,不可重复

    序列化

                var person = new Person
                {
                    Id = 1,
                    Name = "First",
                    Address = new Address { Line1 = "Line1", Line2 = "Line2" }
                };
                using (var file = System.IO.File.Create("Person.bin"))
                {
                    ProtoBuf.Serializer.Serialize(file, person);
                }

    反序列化

    Person newPerson;
    using (var file = System.IO.File.OpenRead("Person.bin"))
    {
        newPerson = ProtoBuf.Serializer.Deserialize<Person>(file);
    }
    使用起来很简单,代码移植也会相当方便,下面我要对比下序列化的文件大小。
    1.使用ProtoBuf序列化1000个对象,查看Person.bin文件大小为:30 KB (29,760 字节)
    List<Person> list = new List<Person>();
                for (var i = 0; i < 1000; i++)
                {
                    var person = new Person
                    {
                        Id = i,
                        Name = "Name"+i,
                        Address = new Address { Line1 = "Line1", Line2 = "Line2" }
                    };
                    list.Add(person);
                }
    
                using (var file = System.IO.File.Create("Person.bin"))
                {
                    ProtoBuf.Serializer.Serialize(file, list);
                }

    2.使用xml序列化1000个对象,Person.xml大小为:152 KB (155,935 字节)

                List<Person> list = new List<Person>();
                for (var i = 0; i < 1000; i++)
                {
                    var person = new Person
                    {
                        Id = i,
                        Name = "Name"+i,
                        Address = new Address { Line1 = "Line1", Line2 = "Line2" }
                    };
                    list.Add(person);
                }
    
                System.Xml.Serialization.XmlSerializer xmlSerizlizer = new System.Xml.Serialization.XmlSerializer(typeof(List<Person>));
                using(var file= System.IO.File.Create("Persion.xml")){
                    xmlSerizlizer.Serialize(file, list);
                }

    3. 使用binary序列化1000个对象,Person.dat大小为:54.1 KB (55,445 字节)

                List<Person> list = new List<Person>();
                for (var i = 0; i < 1000; i++)
                {
                    var person = new Person
                    {
                        Id = i,
                        Name = "Name"+i,
                        Address = new Address { Line1 = "Line1", Line2 = "Line2" }
                    };
                    list.Add(person);
                }
                
                using(var file = new System.IO.FileStream("Person.dat", System.IO.FileMode.Create))
                {
                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter =
                        new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    binaryFormatter.Serialize(file, list);
                }

    image

    在这个实验中ProtoBuf比xml序列化小5倍,比二进制也近小一倍,有人说ProtoBuf比xml可以小到20倍,根据数据的复杂度这是有可能的。ProtoBuf的数据格式做为数据报文有着绝对优势,当然也有个弊端,它是2进制报文,没有xml格式这样的可读性,要想看懂报文内容只能用ProtoBuf反序列化了,不过我认识这基本上不是问题~

    分类: C#
  • 相关阅读:
    delete
    What's an Aggregate Root?
    Mediator Pattern中介者模式
    Domain events: design and implementation
    "ISerializable" should be implemented correctly
    Package version is always 1.0.0 with dotnet pack
    CA1005: Avoid excessive parameters on generic types
    Event Sourcing pattern
    Command and Query Responsibility Segregation (CQRS) pattern
    Implementing event-based communication between microservices (integration events)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4228610.html
Copyright © 2011-2022 走看看