C#序列化和反序列化
目录
序列化(Serialization)和 反序列化(DeSerialization)
序列化(Serialization)和 反序列化(DeSerialization)
序列化(Serialization):是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。反序列化是序列化的反向操作,将文件还原为对象。
BinaryFormatter和SoapFormatter
.NET提供了一个接口System.Runtime.Serialization.Formatter。定义了实现序列化和反序列化所需的操作,并提供了两个实现接口的类:BinaryFormatter和SoapFormatter。
BinaryFormatter:用于将对象序列化为二进制数据。
SoapFormatter:用于将对象序列化为人接直接可读的文本格式,这个文本是用SOAP来描述的。(SOAP全称为简单对象访问协议Simple Object Access Protocol)是一种轻量级的,基于XML协议的。在使用SoapFormatter生成文件(相较于BinaryFormatter生成文件)较大。(下面有举例)
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
提示:在使用System.Runtime.Serialization.Formatters.Soap未找到时,可能需要引入System.Runtime.Serialization.Formatters.Soap。
IFormatter
IFormatter中最重要的两个方法就是Serialize()和Deserialize(),分别用于序列化和反序列化。IFormatter接受的是Stream基类,所以可以序列化到任何流类型中,而不仅限于文件流。
//
// 摘要:
// 反序列化所提供流中的数据并重新组成对象图形。
//
// 参数:
// serializationStream:
// 包含要反序列化的数据的流。
//
// 返回结果:
// 反序列化的图形的*对象。
object Deserialize(Stream serializationStream);
//
// 摘要:
// 将对象或具有给定根的对象图形序列化为所提供的流。
//
// 参数:
// serializationStream:
// 格式化程序在其中放置序列化数据的流。此流可以引用多种后备存储区(如文件、网络、内存等)。
//
// graph:
// 要序列化的对象或对象图形的根。将自动序列化此根对象的所有子对象。
void Serialize(Stream serializationStream, object graph);
Serializable和NonSerialized
Serializable:假如你想对某个类进行序列化,需要在定义的类的名字上面加上: [Serializable] ,说明该类是可序列化的,否则将会抛出异常:‘未标记为可序列化’。
NonSerialized:假如你想对某个已标记可序列化类中的某个字段不想序列化,可使用[NonSerialized]标记,在序列化时就会把
它排除在外。需要注意的是NonSerialized只能加在字段上,不能加在属性上。
[Serializable]//标记该类可序列化
class NlikiISerializable : ISerializable
{
[NonSerialized]//标记该字段不可序列化
private string _nliki;
}
事件响应
对于一些比较敏感的数据(比如账号、密码等),我们不希望他出现在序列化文件中。我们可以使用NonSerialized标记,不过这样的反序列化后对象的状态就不完整了。解决这样的办法可以在序列化前将其进行加密,在反序列化后进行解密还原。在序列化或者反序列化的过程中需要注入一些特定的逻辑。.NET提供了四个序列化和反序列化特性标记来实现这一过程:
OnSerializing(序列化开始前)、OnSerialized(序列化开始后)、OnDeserializing(反序列化开始前)、OnDeserialized(反序列化开始后)。
[Serializable]
class NlikiSerialize
{
[NonSerialized]
private string _nliki="abc";
[OnSerializing]
void OnSerilazing() {
this._nliki = this._nliki.Replace("a","o");
}
}
ISerializable 自定义序列化
自定义序列化只需要实现ISerializable接口就行了。其中SerializationInfo(包含一组AddValue方法和一组Get<Type>方法)有点类似于BinaryWriter和BinaryReader,用于写入和读取对象的属性值。
namespace System.Runtime.Serialization
{
public interface ISerializable
{
void GetObjectData(SerializationInfo info, StreamingContext context);
}
}
简单举例:
namespace ISerializableAuthorNliki
{
[Serializable]
class TestISerializable : ISerializable
{
[NonSerialized]
private string[] _strSer;
public string[] StrSer
{
get { return this._strSer; }
set { this._strSer = value; }
}
public TestISerializable() { }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("props", _strSer, typeof(string[]));
}
}
}
static void Main(string[] args)
{
string path1 = @"C:\Users\YYS\Desktop\Serializable\nliki1.nliki";
string path2 = @"C:\Users\YYS\Desktop\Serializable\nliki2.nliki";
TestISerializable test = new TestISerializable();
string[] str=new string[10000000];
string st = "I'm Nliki. 中文:南回";
for (var i=0;i< str.Length; i++) {
str[i] = st;
}
test.StrSer = str;
IFormatter formatter1 = new BinaryFormatter();
using (FileStream fs = new FileStream(path1, FileMode.OpenOrCreate))
{
formatter1.Serialize(fs, test);
fs.Close();
}
SoapFormatter formatter2 = new SoapFormatter();
using (FileStream fs = new FileStream(path2, FileMode.OpenOrCreate))
{
formatter2.Serialize(fs, test);
fs.Close();
}
Console.ReadKey();
}
}
运行结果:
1:生成的文件大小不一样
2:可读性不一样(由于文件不好展示,这里就不展示了。nliki1文件人可读性几乎不行;nliki2文件人为可读)
下一篇: Java多线程中的Balking模式详解