.net中的序列化和反序列化之二进制序列化
在介绍序列化的时候我们首先要搞清楚什么是序列化以及为什么要使用序列化。
序列化的官方定义是:将对象状态转换为可保持或可传输的形式的过程。首先,什么是对象状态,对象状态就是对象在某个时刻具有的特征,其实简单一点就是这个对象。那么什么是可保持?我们知道,对象是有生存期的,一旦对象过了生存期我们就无法访问到这个对象。可保持的意思就是打破对象的生存期。使对象具有持久的访问方式。典型的可保持就是我们的磁盘保存了。那么什么是可传输?传输的是意思就是在不同的地点之间传递某个物品。而我们这里就是在不同的程序,组件之间传递某个对象。现在最后一个问题?为什么要使用序列化。其实一个话就可以概述,就是在不同的程序,应用程序域,组件之间以一定的格式共享或传输某个对象。比如应用程序A想访问应用程序B里的一个对象。那么我们就可以把B里的这个对象序列化到磁盘或者别的课存储介质。然后A就从这个存储介质里访问B的这个对象。还有一种情况就是典型的webservice了。在网络之间传输对象。
那么我们来给序列化下一个定义:以某种格式编码对象的状态,然后存储到可存储介质中以便以后其他应用程序可访问或者公开对象以便其他程序通过网络访问数据。
反序列化:将得到的具有某种格式编码的对象转换为原始对象的精确副本。
序列化有两种,第一种是二进制序列化,第二种是XML序列化。我们先介绍二进制序列化再介绍XML序列化
二进制序列化
二进制序列化就是将对象状态存存储到存储介质中的过程。这个过程是
1:将对象的公共字段,私有字段以及类(包括含有该类的程序集)的名称转换为字节流
2:将字节流写入数据流
3:反序列化对象,得到原始对象的准确克隆。
下面来看一个简单的示例,怎么样序列化一个对象,首先我们创建一个实体类,用来序列化。
[Serializable]
public class Person
{
private int _personId;
public int PersonId
{
get { return _personId; }
set { _personId = value; }
}
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
public Person() { }
public Person(int personId, string firstName, string lastName)
{
this.PersonId = PersonId;
this.FirstName = firstName;
this.LastName = lastName;
}
}
很简单的一个实体类,但是一定要注意一点,就是类必须打上[Serializable]属性,来表明这个类可以实例化。否则类就不能被序列化。[Serializable]不支持继承,也就是说,如果我们现在要写一个类继承Perosn。子类不能继承[Serializable]标记,我们必须手动来给子类添加这个标记。
实体类准备好了,下面我们来示例话这个实体类
static void Main(string[] args)
{
Stream stream = null;
try
{
Person person = new Person(1, "Edrick", "Liu");
IFormatter formatter = new BinaryFormatter();
stream = new FileStream("D:\\Person.bin", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, person);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
stream.Close();
}
finally
{
stream.Close();
}
Console.WriteLine("The Person was Serializabled");
Console.Read();
}
首先我们要引用命名空间
using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.IO;
根据上面我们介绍序列化的过程我们来看看代码
我们首先实例化对象用来序列化,然后定义个序列化器IFormatter,提供了序列化的功能。我们用BinaryFormatter实例化这个序列化器。因为BinaryFormatter实现了这个接口所以我们实际上是实例化了BinaryFormatter。这里我们也可以使用BinaryFormatter来实例化。然后我们实例化一个文件流。最后把流写入磁盘。这就是一个简单的,完整的序列化一个对象。在这里我们可以用记事本打开这个文件看看,虽然有些乱码,但是可以看到我们的字段和值。这里也要注意一点,BinaryFormatter会序列化公有字段和私有字段。文章的后面我们会介绍怎么又选择性的序列化。
下面来看看怎么反序列化对象
#region -----反序列化对象
Stream stream = null;
try
{
IFormatter formatter = new BinaryFormatter();
stream = new FileStream("D:\\Person1.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
Person perosn = (Person)formatter.Deserialize(stream);
Console.WriteLine(perosn.PersonId);
Console.WriteLine(perosn.FirstName);
Console.WriteLine(perosn.LastName);
Console.Read();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
if (stream != null)
{
stream.Close();
}
Console.Read();
}
finally
{
if (stream != null)
{
stream.Close();
}
}
#endregion
其实也是很简单的,我们只需要实例化一个序列化器,一个流对象。然后调用Deserializable()。这个方法返回的是Object,所以我们需要显示转换一下。其实这里的序列化器只是一个格式的定义者,就是序列化与反序列化都能理解的一种数据格式。就是反序列化的时候,序列化器知道序列化时候的格式,然后创建对象。以上就是一个简单的二进制序列化的示例。上述示例中,我们不单单是可以使用文件流,还可以使用内存流,网络流。其实是都可以,原理是一样的。只是存储的介质发生了变化而已。所以我们上面说的存储介质不单单指的磁盘。
我们上面说了Iformatter是一个序列化器的接口,Binaryformatter实现了这个接口,那么还有什么类实现这个接口呢?还有SoapFormatter。但是在.netframerwork3.5中这个类已经过时。所以这里就不做多的介绍了。
刚刚我们提到了,二进制序列化会把公有字段和私有地段进行序列化,但是如果我们为了安全起见不想序列化某个字段,那该怎么办,很简单,给成员变量加[NonSerialized]属性标记就行了。这样这个字段就不会被序列化了。还有一点要特别注意的是,[NonSerialized]标记只能在成员变量上使用,不能标记在属性上,否则编译会报错。
简单的序列化就介绍完了,下面我会介绍一下序列化比较高级一点的功能和XML的序列化

浙公网安备 33010602011771号