赞
踩
Protobuf实际是一套类似Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。通信时所传递的信息是通过Protobuf定义的message数据结构进行打包,然后编译成二进制的码流再进行传输或者存储。
protobuf全称Protocol Buffers,简称GPB、PB,是QQ等IM采用的协议,比XML、XMPP(环信)、JSON、结构体等所有传输效果都高的一种传输协议,由谷歌发明,其效率一般是XM的20倍以上,JSON的10倍以上,是一种游戏中普遍采用的消息协议。
简单说就是Google公司发明的,用来进行序列化和反序列化的。
和json、xml类似,Protobuf有几个突出的优点:
当然,其也有一定的缺点:由于序列化为了二进制数组,序列化后完全不可读。
Protobuf-Net是Marc Gravell在protobuf基础上修改的.net版本,相比Google的代码,其在.Net环境下使用起来更加简单。本篇文章就介绍一下Protobuf的使用。
Protobuf-Net的Github地址
我们在进行vs开发的时候,安装Protobuf-Net很简单,直接在Nuget包管理器中搜索Protobuf-Net即可。
如图。
1.进入包管理器
2.搜索Protobuf-Net,并安装
核心代码就是Serializer.Serialize方法,该方法有两个参数,第二个参数是要序列化的对象,第一个参数是要序列化到的流对象。
例如序列化FileSteam,序列化完成后将直接保存至本地,不必再调用fs.Write、fs.Flush等方法。
using (FileStream fs = File.Create(path))
{
Serializer.Serialize(fs, t);
}
也可使用MemoryStram配合Protobuf-Net来实现对象的深拷贝,就是先将要拷贝的对象序列化然后在反序列化出来。
public static T Clone<T>(T t)
{
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, t);
ms.Position = 0;
return Serializer.Deserialize<T>(ms);
}
}
或者直接使用Serializer.DeepClone(t)方法(其内部实现与上面我们的方法相同)。
反序列化也很简单,核心代码是Serializer.Deserialize(),传入流对象,即可得到反序列化后的对象。
如反序列化文件。
public static T Read<T>(string path)
{
using (FileStream fs = File.OpenRead(path))
{
return Serializer.Deserialize<T>(fs);
}
}
对于需要序列化的类,需要添加上对应的特性。
一是给类添加[ProtoBuf.ProtoContract]特性,类中的字段或属性添加[ProtoBuf.ProtoMember(1)]特性。
如下:
[ProtoBuf.ProtoContract]
internal class Student : Pearson
{
[ProtoBuf.ProtoMember(1, IsRequired = true)]
public int Id { get; set; }
public Student() { }
public override string ToString()
{
return $"id:{Id} name:{Name} age:{Age} gender:{Gender}";
}
}
其中[ProtoBuf.ProtoMember(1, IsRequired = true)],数字1表示tag,只能为正数,建议从1开始;IsRequired表示是否必要,方便向后兼容,什么意思呢?比方说我们之前发布了一个版本,协议已经定好,现在需要在类中添加一些内容,这些内容就需要加上IsRequired = false,这样我们的程序虽然添加了新的内容,但是仍然可以打开之前的数据而不会报错。
二是在有继承的情况时,基类需要添加上[ProtoBuf.ProtoInclude(100, typeof(Student))]特性。
一个基类可能有多个子类,有几个子类,基类上就添加几个[ProtoBuf.ProtoInclude(100, typeof(Student))]。
其中的100也是tag,和ProtoBuf.ProtoMember的tag类似,但是ProtoBuf.ProtoInclude的tag要是唯一的,不能和基类上其他的ProtoBuf.ProtoInclude的tag相同,也不能和基类中的ProtoBuf.ProtoMember的tag相同。typeof(T),表示已知的子类。
public enum Gender { Male, Female } [ProtoBuf.ProtoContract] [ProtoBuf.ProtoInclude(100, typeof(Student))] [ProtoBuf.ProtoInclude(101, typeof(Teacher))] // 如这里tag不能设为100、1、2、3 class Pearson { [ProtoBuf.ProtoMember(1, IsRequired = false)] public string Name { get; set; } [ProtoBuf.ProtoMember(2, IsRequired = true)] public Gender Gender { get; set; } [ProtoBuf.ProtoMember(3, IsRequired = true)] public int Age { get; set; } }
完整的测试项目在这。
链接:https://pan.baidu.com/s/16ri31b8F2UxvR5IDxbQP_A
提取码:5sky
TODO 待完成。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。