序列化和反序列化
- 序列化是将对象状态转换为可保持或传输的形式的过程
- 反序列化是将流转换为对象
- 两个过程一起,则保证了数据的存储和传输
应用场景
不仅仅运用于.NET项目中,其它框架的项目中也比较常见。
- 将内存的对象序列化后保存在本地,上传到某些特定位置,如:共享目录、FTP、供第三方系统识别读取
- 与第三方进行通信,对方只能接收二进制类型字节流数据
- 保存Session、Cookie等场景
- 跨平台,跨语言交互等场景
常见序列化格式
- 整体二进制,将实例对象整体序列化成二进制
- xml格式,将实例独享序列化成XML数据格式,多用于WebService
- json格式,将实例化对象序列化成JSON格式,多用于WebService
- Protobuf,即Protocol Buffers,是Google公司开发的一种跨语言和平台的序列化数据结构方式,是一个灵活的、高效的用于序列化数据的协议
示例
[本示例中,为便于比较序列化后内容的大小,将序列化后的内容保存到本地文件,且实现了序列化和反序列化功能。]
- 安装第三方库
序列化JSON和ProtoBuf格式需要安装第三方库,可通过NuGet包管理器进行安装
- Newtonsoft.Json
- protobuf-net
- protobuf-net.Core
- 序列化帮助类接口
为统一调用方式,定义序列化帮助类接口,不同实现方式,只需要实现对应接口即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// Interfaces/ISerializeHelper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
/// 序列化帮助类接口
public interface ISerializeHelper
{
/// 序列化
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="path">序列化后保存路径</param>
void Serialize<T>(T t, string path) where T : class;
/// 反序列化
/// <typeparam name="T"></typeparam>
/// <param name="path">反序列化文件路径</param>
/// <returns></returns>
T Deserialize<T>(string path) where T : class;
}
} - 定义序列化模型Person【注:】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33// Models/Person 定义一个测试类
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
/// 个人信息
[ ]
[ ]
public class Person
{
/// 唯一标识
[ ]
public int Id { get; set; }
/// 姓名
[ ]
public string Name { get; set; }
/// 生日
[ ]
public DateTime Birthday { get; set; }
public override string ToString()
{
return $"Id={Id},Name={Name},Birthday={Birthday.ToString("yyyy-MM-dd HH:mm:ss.fff")}";
}
}
}
- 进行整体二进制序列化时,必须将类标记为Serializable,否则会抛出异常
- Protobuf序列化需要将类标记为ProtoContract,并将需要序列化的属性标记为ProtoMember
- 整体二进制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal class BinHelper : ISerializeHelper
{
public T Deserialize<T>(string path) where T:class
{
string filePath = path;
T t;
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
t = bf.Deserialize(fs) as T;
}
return t;
}
public void Serialize<T>(T t, string path) where T : class
{
string filePath = path;
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, t);
}
}
}
} - XML格式6.JSON格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace ConsoleApp
{
public class XmlHelper : ISerializeHelper
{
public T Deserialize<T>(string path) where T : class
{
string filePath = path;
T t;
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(Person));
object obj = serializer.Deserialize(fs);
t = obj as T;
}
return t;
}
public void Serialize<T>(T t, string path) where T : class
{
string filePath = path;
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(Person));
serializer.Serialize(fs, t);
}
}
}
}
- JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,适用于数据交互的场景,如网站前后端间的数据交互。
- JSON是比XML更简单的一种数据交换格式,采用完全独立于编程语言的文本格式来存储和表示数据。
- 一般采用第三方库Newtonsoft.Json来实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal class JsonHelper : ISerializeHelper
{
public T Deserialize<T>(string path) where T : class
{
T t;
using (StreamReader file = File.OpenText(path))
{
JsonSerializer serializer = new JsonSerializer();
t = (T)serializer.Deserialize(file, typeof(T));
}
return t;
}
public void Serialize<T>(T t, string path) where T : class
{
using (StreamWriter file = File.CreateText(path))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(file, t);
}
}
}
}
- Protobuf格式
- 与XML和JSON相比,Protobuf更小、更快、更便捷
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal class ProtobufHelper : ISerializeHelper
{
public T Deserialize<T>(string path) where T : class
{
string filePath = path;
T t;
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
t = Serializer.Deserialize<T>(fs);
}
return t;
}
public void Serialize<T>(T t, string path) where T : class
{
string filePath = path;
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
Serializer.Serialize<T>(fs, t);
}
}
}
}
- 实例测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79// 序列化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal class Program
{
static void Main(string[] args)
{
Person person = new Person()
{
Id = 1,
Name = "Sleny",
Birthday = DateTime.Now,
};
//bin格式序列化
var binHelper = new BinHelper();
string binPath = @"D:\serialize\person.bin";
binHelper.Serialize<Person>(person, binPath);
//xml格式序列化
var xmlHelper = new XmlHelper();
string xmlPath = @"D:\serialize\person.xml";
xmlHelper.Serialize<Person>(person, xmlPath);
//json格式序列化
var jsonHelper = new JsonHelper();
string jsonPath = @"D:\serialize\person.json";
jsonHelper.Serialize<Person>(person, jsonPath);
//protobuf格式序列化
var protoHelper= new ProtobufHelper();
var protoPath = @"D:\serialize\person.proto";
protoHelper.Serialize<Person>(person, protoPath);
}
}
}
// 反序列化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal class Program
{
static void Main(string[] args)
{
//bin格式反序列化
var binHelper = new BinHelper();
string binPath = @"D:\serialize\person.bin";
var p1 = binHelper.Deserialize<Person>(binPath);
//xml格式反序列化
var xmlHelper = new XmlHelper();
string xmlPath = @"D:\serialize\person.xml";
var p2 = xmlHelper.Deserialize<Person>(xmlPath);
//json格式反序列化
var jsonHelper = new JsonHelper();
string jsonPath = @"D:\serialize\person.json";
var p3 = jsonHelper.Deserialize<Person>(jsonPath);
//protobuf格式反序列化
var protoHelper= new ProtobufHelper();
var protoPath = @"D:\serialize\person.proto";
var p4= protoHelper.Deserialize<Person>(protoPath);
Console.WriteLine($"p1:{p1}");
Console.WriteLine($"p2:{p2}");
Console.WriteLine($"p3:{p3}");
Console.WriteLine($"p4:{p4}");
}
}
}
实例比较
- 整体二进制格式:person.bin 225字节
- XML格式:person.xml 242字节
- JSON格式:person.json 77字节
- Protobuf格式:person.proto 29字节
综上所述:proto < json < bin < xml