Chinar blog :www.chinar.xin
Chinar 的初衷是将一种简单的生活方式带给世人 使有限时间 具备无限可能 |
助力快速完成 Unity 中Protocol Buffer的安装及使用 为新手节省宝贵的时间,避免采坑! |
Chinar 教程效果:
Protocol Buffers
,是Google公司开发的一种数据描述语言,能够将结构化数据序列化,可用于数据存储、通信协议等方面,经常被简称为Protobuf
Protobuf是用于结构化数据序列化的方法,和XML、JSON的作用相似,与它们相比protobuf
:
1. 更简单
2. 数据描述文件大小只是原来的 1/10 至 1/3
3. 解析速度是原来的 20 至 100 倍
4. 减少了二义性
5. 生成了更容易在编程中使用的数据访问类
6. 支持多种编程语言(Java、C++、Python、C#・・・)
你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构
protobuf有两个版本,一个是Google官方的版本,名字叫protobuf-csharp
官方网站(科学上网)
Git地址
另一个是社区版名字叫protobuf-net
,本章讲解的是社区版的下载和使用
首先打开上面的NuGet网站:
下载下来的文件是nupkg格式的文件,我们需要在VS工程里面安装
新建一个VS工程,选择控制台应用:
点击编辑栏里面的 工具
--> NuGet包管理器
--> 程序包管理器控制台
然后会有命令工具弹出
等待命令执行完成
到此protobuf
已安装完毕
我们打开解决方案看到已经引用了protobuf-net
然后打开 工程目录–>工程名文件夹–>packages
–>protobuf-net.2.4.0
–>lib
可以看到有多个版本,我们打开对应工程.Net版本的文件夹,可以看到有protobuf-net.dll
文件
保存 protobuf-net.dll
文件,这个文件可以直接放入Unity中使用,也可以在别的工程引用。
protobuf
支持许多数据类型,我们来看一看
protobuf 数据类型 | 含义 | 对应C#类型 |
---|---|---|
bool |
布尔类型 | bool |
double |
64位浮点数 | double |
float |
64位浮点数 | float |
int32 |
32位整数 | int |
uint32 |
无符号32位整数 | uint |
int64 |
64位整数 | int |
uint64 |
无符号64位整数 | uint |
string |
只能处理 ASCII字符 | string |
bytes |
用于处理多字节的语言字符、如中文 | byte |
enum |
枚举类型 | enum |
message |
可以包含一个自定义的消息类型 | object |
protobuf
的常用修饰符
修饰符 | 含义 |
---|---|
required |
不能为空 |
optional |
可选字段,可以为空 |
repeated |
repeated 代表这个数据可重复,在C#中为一个List链表 |
我们创建一个后缀为 proto
的文本文件,名字叫Game
syntax = "proto2";//指定版本信息
message USERINFO//用户信息
{
optional string Account = 1; //账号
optional string PassWord = 2; //密码
optional string UserName = 3; //用户名
optional uint32 UserId = 4; //用户id
}
message GAMEINFO//游戏信息
{
repeated USERINFO UserInfo = 2;//一个用户信息的链表
}
然后我们需要将proto文件生成对应的cs文件,需要一个工具
提取码:xbt4
解压后打开文件夹,我们的proto
文件应该放在protos
文件夹中,选择run.bat文件,右键编辑
然后会打开一个编辑窗口,里面有一句代码,我们来解析一下这句命令
protogen.exe -i:protos\Game.proto -o:cs\Game.cs -ns:Game
protogen.exe 是我们用到的工具
-i
: 后面为输入的文件,可以为多个文件
-o
: 输出的文件,只能有一个,如果有多个输入文件,那么会同意输出到这一个文件中
-ns
: 输出代码的命名空间
双击运行 run.bat
文件
我们可以在 CS 文件夹中看到生成的 cs 脚本,用 VS 打开
我们再来看看定义的 GAMEINFO
结构
到此,protobuf的书写及转换为指定代码就介绍完成了
首先我封装了
protobuf
的序列化与反序列化的代码,使我们的调用更加方便
using System.IO;
using System;
///
/// 封装protobuf的序列化与反序列化方法
///
///
public class ProtoBufSerialize<T>
{
///
/// 空的构造方法
///
private ProtoBufSerialize()
{
}
///
/// 将对象序列化为二进制的方法
///
/// 要序列化的对象
///
public static byte[] Serialize(T model)
{
try
{
using (MemoryStream ms = new MemoryStream()) //涉及格式转换,需要用到流,将二进制序列化到流中
{
ProtoBuf.Serializer.Serialize<T>(ms, model); //使用ProtoBuf工具的序列化方法
byte[] result = new byte[ms.Length]; //定义二级制数组,保存序列化后的结果
ms.Position = 0; //将流的位置设为0,起始点
ms.Read(result, 0, result.Length); //将流中的内容读取到二进制数组中
return result;
}
}
catch (Exception ex)
{
Console.WriteLine("序列化失败: " + ex.ToString());
return null;
}
}
///
/// 将二进制消息反序列化成对象
///
/// 二进制数据
///
public static T DeSerialize(byte[] msg)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(msg, 0, msg.Length); //将消息写入流中
ms.Position = 0; //将流的位置归0
T result = ProtoBuf.Serializer.Deserialize<T>(ms); //使用ProtoBuf工具反序列化对象
return result;
}
}
catch (Exception ex)
{
Console.WriteLine("反序列化失败: " + ex.ToString());
return default(T);
}
}
}
将我们编译好的Game.cs文件添加进工程中,然后再添加一个测试类 TestProtobuf
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Game;
namespace ProtobufProject
{
public class TestProtobuf
{
///
/// 测试proto序列化
///
/// 账号
/// 密码
/// 用户名
/// id
///
public byte[] Write(string account, string password, string name, int id)
{
USERINFO userinfo = new USERINFO();
userinfo.Account = account;
userinfo.PassWord = password;
userinfo.UserName = name;
userinfo.UserId = (uint)id;
byte[] data = ProtoBufSerialize<USERINFO>.Serialize(userinfo);//序列化数据
return data;
}
///
/// 这是一个创建文件的方法
///
/// 保存文件的路径
/// 文件的字节数组
/// 数据长度
public void CreatFile(string path, byte[] file, int length)
{
Stream sw;
FileInfo File = new FileInfo(path);
if (!File.Exists)
{
sw = File.Create();
}
else
{
return;
}
sw.Write(file, 0, length);
sw.Close();
sw.Dispose();
}
}
}
我们在Main方法处写下代码:
static void Main(string[] args)
{
TestProtobuf testPro = new TestProtobuf();
byte[] result= testPro.Write("account","123","Chinar",666);//将数据信息传入
testPro.CreatFile("C:/LY_VS_Project/ProtobufProject/ProtobufProject/Test.txt",result,result.Length);//写入本地
}
我们在
TestProtobuf
类中添加一个方法,用来读取本地的文件并返回一个byte数组
///
/// 读取文件
///
/// 文件路径
///
public byte[] ReadFile(string path)
{
//读取文件
FileStream fs = File.OpenRead(path);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
return buffer;
}
然后我们在Main方法中测试一下
static void Main(string[] args)
{
TestProtobuf testPro = new TestProtobuf();
//byte[] result= testPro.Write("chinar","123","Chinar",666);
//testPro.CreatFile("C:/LY_VS_Project/ProtobufProject/ProtobufProject/Test.txt",result,result.Length);
//读取之前写入本地的数据并反序列化
USERINFO userinfo = ProtoBufSerialize<USERINFO>.DeSerialize(testPro.ReadFile("C:/LY_VS_Project/ProtobufProject/ProtobufProject/Test.txt"));
Console.WriteLine(userinfo.Account + "===" + userinfo.PassWord + "===" + userinfo.UserName + "===" + userinfo.UserId);
Console.ReadKey();
}
测试结果没有问题,以上就是protobuf的序列化与反序列化
项目文件为 VS 工程:
下载 即可使用
Chinar 提供一站式《零》基础教程 使有限时间 具备无限可能! |
Chinar 知你所想,予你所求!( Chinar Blog )
本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究
对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: [email protected]
对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址