序列化是指将对象转换成字节流,从而存储对象或将对象传输到内存、数据库或文件的过程。 它的主要用途是保存对象的状态,以便能够在需要时重新创建对象。 反向过程称为“反序列化”。
序列化的工作原理
下图展示了序列化的整个过程。
对象序列化
若要序列化对象,需要具有要序列化的对象、包含已序列化对象的一个流,以及一个 Formatter。
将 SerializableAttribute 特性应用于某个类型,以指示此类型的实例可以被序列化,具体做法在类之前加[Serializable]。
如果想让类中的某个字段不可序列化,请应用 NonSerializedAttribute 特性,具体做法在字段之前加[NonSerialized]。
C#代码实现:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace NetFrame
{
public class SerializeUtil
{
/// <summary>
/// 对象序列化
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static byte[] Encode(object value)
{
//创建编码解码的内存流对象
MemoryStream ms = new MemoryStream();
//二进制流序列化对象
BinaryFormatter bw = new BinaryFormatter();
//将obj对象序列化成二进制数据 写入到 内存流
bw.Serialize(ms, value);
byte[] result = new byte[ms.Length];
//将流数据 拷贝到结果数组
Buffer.BlockCopy(ms.GetBuffer(), 0, result, 0, (int)ms.Length);
ms.Close();
return result;
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static object Decode(byte[] value)
{
//创建编码解码的内存流对象 并将需要反序列化的数据写入其中
MemoryStream ms = new MemoryStream(value);
//二进制流序列化对象
BinaryFormatter bw = new BinaryFormatter();
//将流数据反序列化为obj对象
object result = bw.Deserialize(ms);
ms.Close();
return result;
}
}
}
二进制和 XML 序列化
二进制序列化使用二进制编码来生成精简的序列化以供使用,如基于存储或套接字的网络流。
XML 序列化将对象的公共字段和属性或方法的参数和返回值序列化成符合特定 XML 架构定义语言 (XSD) 文档要求的 XML 流。
首先写一个需要序列化的类:
[Serializable]
public class ConfigMD5Data
{
public string fileName;
public string excelMD5;
public List<string> binaryMD5List;
public List<string> classNameList;
public List<string> typeNameList;
[NonSerialized]
public bool md5Changed;
[NonSerialized]
public bool classNameChanged;
[NonSerialized]
public bool binaryChanged;
}
[Serializable]
public class ConfigMD5
{
public List<ConfigMD5Data> m_ConfigMD5List = new List<ConfigMD5Data>();
}
二进制序列化的C#实现:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace StructScript
{
class BinaryFormatterTest
{
private static string m_ConfigMD5Path1;
private static ConfigMD5 m_ConfigList;
private static void Main(string[] args)
{
m_ConfigMD5Path1 = "config.bytes";
m_ConfigList = new ConfigMD5();
for (int i = 0; i < 5; i++)
{
ConfigMD5Data data = new ConfigMD5Data();
data.fileName = "test" + i;
m_ConfigList.m_ConfigMD5List.Add(data);
}
Serialize();
Deserialize();
Console.ReadLine();
}
private static void Serialize()
{
FileStream fs = new FileStream(m_ConfigMD5Path1, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, m_ConfigList);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
}
finally
{
fs.Close();
}
}
private static void Deserialize()
{
if (File.Exists(m_ConfigMD5Path1))
{
FileStream fs = new FileStream(m_ConfigMD5Path1, FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
m_ConfigList = formatter.Deserialize(fs) as ConfigMD5;
int count = m_ConfigList.m_ConfigMD5List.Count;
for (int i = 0; i < count; i++)
{
ConfigMD5Data data = m_ConfigList.m_ConfigMD5List[i];
Console.WriteLine(data.fileName);
}
}
catch (SerializationException e)
{
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
}
finally
{
fs.Close();
}
}
}
[Serializable]
public class ConfigMD5Data
{
public string fileName;
public string excelMD5;
public List<string> binaryMD5List;
public List<string> classNameList;
public List<string> typeNameList;
[NonSerialized]
public bool md5Changed;
[NonSerialized]
public bool classNameChanged;
[NonSerialized]
public bool binaryChanged;
}
[Serializable]
public class ConfigMD5
{
public List<ConfigMD5Data> m_ConfigMD5List = new List<ConfigMD5Data>();
}
}
}
输出结果:
Xml序列化C#实现:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace StructScript
{
public class XmlFormatterTest
{
private static string m_ConfigMD5Path;
private static ConfigMD5 m_ConfigList;
private static void Main(string[] args)
{
m_ConfigMD5Path = "config.xml";
m_ConfigList = new ConfigMD5();
for (int i = 0; i < 5; i++)
{
ConfigMD5Data data = new ConfigMD5Data();
data.fileName = "test" + i;
m_ConfigList.m_ConfigMD5List.Add(data);
}
SaveXml();
LoadXml();
Console.ReadLine();
}
public static bool SaveXml()
{
DeleteFile(m_ConfigMD5Path);
using (StreamWriter sw = new StreamWriter(m_ConfigMD5Path, false, Encoding.UTF8))
{
XmlSerializer serializer = new XmlSerializer(typeof(ConfigMD5));
try
{
serializer.Serialize(sw, m_ConfigList);
}
catch (Exception e)
{
Console.WriteLine("Load ConfigMD5 fail, error: " + e.Message);
}
}
return true;
}
public static bool DeleteFile(string filePath)
{
if (File.Exists(filePath))
{
File.Delete(filePath);
return true;
}
return false;
}
public static void LoadXml()
{
if (File.Exists(m_ConfigMD5Path))
{
try
{
using (StreamReader sr = new StreamReader(m_ConfigMD5Path, Encoding.UTF8))
{
XmlSerializer serializer = new XmlSerializer(typeof(ConfigMD5));
m_ConfigList = serializer.Deserialize(sr) as ConfigMD5;
int count = m_ConfigList.m_ConfigMD5List.Count;
for (int i = 0; i < count; i++)
{
ConfigMD5Data data = m_ConfigList.m_ConfigMD5List[i];
Console.WriteLine(data.fileName);
}
}
}
catch (Exception e)
{
Console.WriteLine("Load ConfigMD5 fail, error: " + e.Message);
}
}
}
[Serializable]
public class ConfigMD5Data
{
public string fileName;
public string excelMD5;
public List<string> binaryMD5List;
public List<string> classNameList;
public List<string> typeNameList;
[NonSerialized]
public bool md5Changed;
[NonSerialized]
public bool classNameChanged;
[NonSerialized]
public bool binaryChanged;
}
[Serializable]
public class ConfigMD5
{
public List<ConfigMD5Data> m_ConfigMD5List = new List<ConfigMD5Data>();
}
}
}
输出结果:
总结:
在二进制序列化中,所有成员(包括只读成员)都会被序列化,且性能也会有所提升。 XML 序列化可提高代码可读性,以及对象共享和使用的灵活性,从而实现互操作性。