原文:http://blog.csdn.net/zhoufoxcn/archive/2009/03/11/3978874.aspx?
.net中對象序列化技術淺談 (轉)
序列化是將對象狀態轉換為可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換為對象。這兩個過程結合起來,可以輕松地存儲和傳輸數據。例如,可以序列化一個對象,然后使用 HTTP 通過 Internet 在客戶端和服務器之間傳輸該對象。反之,反序列化根據流重新構造對象。此外還可以將對象序列化后保存到本地,再次運行的時候可以從本地文件中“恢復”對象到序列化之前的狀態。
在.net中有提供了幾種序列化的方式:
二進制序列化
XML序列化
SOAP序列化
二進制序列化
所謂二進制序列化,指的是對象序列化之后是二進制形式的。二進制序列化是通過BinaryFormatter類來實現的,這個類位于System.Runtime.Serialization.Formatters.Binary命名空間下。
XML序列化
所謂XML序列化,是指對象序列化之后的結果是XML形式的。保存XML序列化是通過XmlSerializer 類來實現的, 這個類位于System.Xml.Serialization命名空間下。
SOAP序列化
所謂SOAP序列化是指對象序列化之后的結果符合SOAP協議,也就是可以通過SOAP協議傳輸(不知道SOAP協議?百度一下吧)。SOAP序列化是通過SoapFormatter類來實現的,這個類位于System.Runtime.Serialization.Formatters.Soap命名空間下,并且需要注意需要手動添加對這個命名空間的引用,如下圖所示:
?
下面編寫一個類用于序列化和反序列化,這個類的代碼如下:
using System;??
using System.Collections.Generic;??
using System.Text;??
?
namespace MySerializeDemo??
{??
??? [Serializable]??
??? /// <summary>??
??? /// 要序列化的對象??
??? /// 作者:周公??
??? /// 編寫時間:2009-03-10??
??? /// </summary>??
??? public class MyObject??
??? {??
??????? //[NonSerialized]??
??????? private string name;??
??????? private DateTime birthday;??
??????? private string homePlace;??
??????? /// <summary>??
??????? /// 出生地??
??????? /// </summary>??
??????? public string HomePlace??
??????? {??
??????????? get { return homePlace; }??
??????????? set { homePlace = value; }??
??????? }??
???
??????? /// <summary>??
??????? /// 生日??
??????? /// </summary>??
??????? public DateTime Birthday??
??????? {??
??????????? get { return birthday; }??
??????????? set { birthday = value; }??
??????? }??
???
??????? /// <summary>??
??????? /// 姓名??
??????? /// </summary>??
??????? public string Name??
??????? {??
??????????? get { return name; }??
??????????? set { name = value; }??
??????? }??
???
??????? /// <summary>??
??????? /// 年齡??
??????? /// </summary>??
??????? public int Age??
??????? {??
??????????? get { return DateTime.Now.Year - birthday.Year; }??
??????? }??
??????? /// <summary>??
??????? /// override了ToString()方法??
??????? /// </summary>??
??????? /// <returns></returns>??
??????? public override string ToString()??
??????? {??
??????????? return string.Format("姓名:{0},生日:{1},出生地:{2},年齡:{3}",name,birthday,homePlace,Age);??
??????? }??
???
??? }??
}?
using System;
using System.Collections.Generic;
using System.Text;
namespace MySerializeDemo
{
??? [Serializable]
??? /// <summary>
??? /// 要序列化的對象
??? /// 作者:周公
??? /// 編寫時間:2009-03-10
??? /// </summary>
??? public class MyObject
??? {
??????? //[NonSerialized]
??????? private string name;
??????? private DateTime birthday;
??????? private string homePlace;
??????? /// <summary>
??????? /// 出生地
??????? /// </summary>
??????? public string HomePlace
??????? {
??????????? get { return homePlace; }
??????????? set { homePlace = value; }
??????? }
?
??????? /// <summary>
??????? /// 生日
??????? /// </summary>
??????? public DateTime Birthday
??????? {
??????????? get { return birthday; }
??????????? set { birthday = value; }
??????? }
?
??????? /// <summary>
??????? /// 姓名
??????? /// </summary>
??????? public string Name
??????? {
??????????? get { return name; }
??????????? set { name = value; }
??????? }
?
??????? /// <summary>
??????? /// 年齡
??????? /// </summary>
??????? public int Age
??????? {
??????????? get { return DateTime.Now.Year - birthday.Year; }
??????? }
??????? /// <summary>
??????? /// override了ToString()方法
??????? /// </summary>
??????? /// <returns></returns>
??????? public override string ToString()
??????? {
??????????? return string.Format("姓名:{0},生日:{1},出生地:{2},年齡:{3}",name,birthday,homePlace,Age);
??????? }
?
??? }
}
下面是分別用上面的三個類進行序列化和反序列化的代碼:
view plaincopy to clipboardprint?
using System;??
using System.Collections.Generic;??
using System.Text;??
using System.IO;??
using System.Runtime.Serialization.Formatters;??
using System.Runtime.Serialization.Formatters.Binary;??
using System.Runtime.Serialization.Formatters.Soap;??
using System.Xml.Serialization;??
?
namespace MySerializeDemo??
{??
??? class Program??
??? {??
??????? static void Main(string[] args)??
??????? {??
??????????? MyObject obj = new MyObject();??
??????????? obj.Birthday = new DateTime(1979, 11, 7);??
??????????? obj.HomePlace = "湖北";??
??????????? obj.Name = "周公";??
??????????? Console.WriteLine("========使用BinaryFormatter類進行序列化和反序列化。====");??
??????????? BinarySerialize(obj);??
??????????? BinaryDeserialize("C:\\MyObject.dat");??
??????????? Console.WriteLine("========使用SoapFormatter類進行序列化和反序列化。====");??
??????????? SOAPSerialize(obj);??
??????????? SOAPDeserialize("C:\\MyObject.soap");??
??????????? Console.WriteLine("========使用XmlSerializer類進行序列化和反序列化。====");??
??????????? XMLSerialize(obj);??
??????????? XMLDeserialize("C:\\MyObject.xml");??
??????? }??
??????? /// <summary>??
??????? /// 二進制序列化對象??
??????? /// </summary>??
??????? /// <param name="obj"></param>??
??????? public static void BinarySerialize(MyObject obj)??
??????? {??
??????????? using (FileStream stream = new FileStream("C:\\MyObject.dat", FileMode.Create, FileAccess.Write))??
??????????? {??
??????????????? BinaryFormatter formater = new BinaryFormatter();??
??????????????? formater.Serialize(stream, obj);??
??????????????? Console.WriteLine("對象已經被序列化。" + obj.ToString());??
??????????? }??
??????? }??
??????? /// <summary>??
??????? /// 二進制反序列化??
??????? /// </summary>??
??????? /// <param name="fileName"></param>??
??????? public static void BinaryDeserialize(string fileName)??
??????? {??
??????????? using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))??
??????????? {??
??????????????? BinaryFormatter formater = new BinaryFormatter();??
??????????????? MyObject obj=(MyObject)formater.Deserialize(stream);??
??????????????? Console.WriteLine("對象已經被反序列化。" + obj.ToString());??
??????????? }??
??????? }??
?
??????? /// <summary>??
??????? /// 二進制序列化對象??
??????? /// </summary>??
??????? /// <param name="obj"></param>??
??????? public static void SOAPSerialize(MyObject obj)??
??????? {??
??????????? using (FileStream stream = new FileStream("C:\\MyObject.soap", FileMode.Create, FileAccess.Write))??
??????????? {??
??????????????? SoapFormatter formater = new SoapFormatter();??
??????????????? formater.Serialize(stream, obj);??
??????????????? Console.WriteLine("對象已經被序列化。" + obj.ToString());??
??????????? }??
??????? }??
??????? /// <summary>??
??????? /// 二進制反序列化??
??????? /// </summary>??
??????? /// <param name="fileName"></param>??
??????? public static void SOAPDeserialize(string fileName)??
??????? {??
??????????? using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))??
??????????? {??
??????????????? SoapFormatter formater = new SoapFormatter();??
??????????????? MyObject obj = (MyObject)formater.Deserialize(stream);??
??????????????? Console.WriteLine("對象已經被反序列化。" + obj.ToString());??
??????????? }??
??????? }??
??????? /// <summary>??
??????? /// XML序列化??
??????? /// </summary>??
??????? /// <param name="obj"></param>??
??????? public static void XMLSerialize(MyObject obj)??
??????? {??
??????????? using (FileStream stream = new FileStream("C:\\MyObject.xml", FileMode.Create, FileAccess.Write))??
??????????? {??
??????????????? XmlSerializer serializer = new XmlSerializer(typeof(MyObject));??
??????????????? serializer.Serialize(stream, obj);??
??????????????? Console.WriteLine("對象已經被序列化。" + obj.ToString());??
??????????? }??
??????? }??
??????? /// <summary>??
??????? /// XML反序列化??
??????? /// </summary>??
??????? /// <param name="fileName"></param>??
??????? public static void XMLDeserialize(string fileName)??
??????? {??
??????????? using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))??
??????????? {??
??????????????? XmlSerializer serializer = new XmlSerializer(typeof(MyObject));??
??????????????? MyObject obj = (MyObject)serializer.Deserialize(stream);??
??????????????? Console.WriteLine("對象已經被反序列化。" + obj.ToString());??
??????????? }??
??????? }??
??? }??
}?
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Xml.Serialization;
namespace MySerializeDemo
{
??? class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? MyObject obj = new MyObject();
??????????? obj.Birthday = new DateTime(1979, 11, 7);
??????????? obj.HomePlace = "湖北";
??????????? obj.Name = "周公";
??????????? Console.WriteLine("========使用BinaryFormatter類進行序列化和反序列化。====");
??????????? BinarySerialize(obj);
??????????? BinaryDeserialize("C:\\MyObject.dat");
??????????? Console.WriteLine("========使用SoapFormatter類進行序列化和反序列化。====");
??????????? SOAPSerialize(obj);
??????????? SOAPDeserialize("C:\\MyObject.soap");
??????????? Console.WriteLine("========使用XmlSerializer類進行序列化和反序列化。====");
??????????? XMLSerialize(obj);
??????????? XMLDeserialize("C:\\MyObject.xml");
??????? }
??????? /// <summary>
??????? /// 二進制序列化對象
??????? /// </summary>
??????? /// <param name="obj"></param>
??????? public static void BinarySerialize(MyObject obj)
??????? {
??????????? using (FileStream stream = new FileStream("C:\\MyObject.dat", FileMode.Create, FileAccess.Write))
??????????? {
??????????????? BinaryFormatter formater = new BinaryFormatter();
??????????????? formater.Serialize(stream, obj);
??????????????? Console.WriteLine("對象已經被序列化。" + obj.ToString());
??????????? }
??????? }
??????? /// <summary>
??????? /// 二進制反序列化
??????? /// </summary>
??????? /// <param name="fileName"></param>
??????? public static void BinaryDeserialize(string fileName)
??????? {
??????????? using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
??????????? {
??????????????? BinaryFormatter formater = new BinaryFormatter();
??????????????? MyObject obj=(MyObject)formater.Deserialize(stream);
??????????????? Console.WriteLine("對象已經被反序列化。" + obj.ToString());
??????????? }
??????? }
??????? /// <summary>
??????? /// 二進制序列化對象
??????? /// </summary>
??????? /// <param name="obj"></param>
??????? public static void SOAPSerialize(MyObject obj)
??????? {
??????????? using (FileStream stream = new FileStream("C:\\MyObject.soap", FileMode.Create, FileAccess.Write))
??????????? {
??????????????? SoapFormatter formater = new SoapFormatter();
??????????????? formater.Serialize(stream, obj);
??????????????? Console.WriteLine("對象已經被序列化。" + obj.ToString());
??????????? }
??????? }
??????? /// <summary>
??????? /// 二進制反序列化
??????? /// </summary>
??????? /// <param name="fileName"></param>
??????? public static void SOAPDeserialize(string fileName)
??????? {
??????????? using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
??????????? {
??????????????? SoapFormatter formater = new SoapFormatter();
??????????????? MyObject obj = (MyObject)formater.Deserialize(stream);
??????????????? Console.WriteLine("對象已經被反序列化。" + obj.ToString());
??????????? }
??????? }
??????? /// <summary>
??????? /// XML序列化
??????? /// </summary>
??????? /// <param name="obj"></param>
??????? public static void XMLSerialize(MyObject obj)
??????? {
??????????? using (FileStream stream = new FileStream("C:\\MyObject.xml", FileMode.Create, FileAccess.Write))
??????????? {
??????????????? XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
??????????????? serializer.Serialize(stream, obj);
??????????????? Console.WriteLine("對象已經被序列化。" + obj.ToString());
??????????? }
??????? }
??????? /// <summary>
??????? /// XML反序列化
??????? /// </summary>
??????? /// <param name="fileName"></param>
??????? public static void XMLDeserialize(string fileName)
??????? {
??????????? using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
??????????? {
??????????????? XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
??????????????? MyObject obj = (MyObject)serializer.Deserialize(stream);
??????????????? Console.WriteLine("對象已經被反序列化。" + obj.ToString());
??????????? }
??????? }
??? }
}
這個程序的運行效果如下:
?
可見通過上面三個類都能實現將對象序列化保存,并且都能反序列化還原到對象被序列化之前的狀態(這正是序列化意義所在,能保存對象運行時的狀態并且還能還原)。如果運行上面的代碼會在C盤根目錄下創建三個文件,分別是MyObject.dat、MyObject.soap和MyObject.xml文件,因為MyObject.dat是二進制文件,所以無法查看文件的內容,但是我們可以打開MyObject.soap和MyObject.xml這兩個文件來比較一下有什么區別。
MyObject.soap文件的后綴雖然是.soap,但是還是可以用記事本打開的,下面是MyObject.soap文件的內容:
view plaincopy to clipboardprint?
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">?
<SOAP-ENV:Body>?
<a1:MyObject id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MySerializeDemo/MySerializeDemo%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">?
<name id="ref-3">周公</name>?
<birthday>1979-11-07T00:00:00.0000000+08:00</birthday>?
<homePlace id="ref-4">湖北</homePlace>?
</a1:MyObject>?
</SOAP-ENV:Body>?
</SOAP-ENV:Envelope>?
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:MyObject id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MySerializeDemo/MySerializeDemo%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<name id="ref-3">周公</name>
<birthday>1979-11-07T00:00:00.0000000+08:00</birthday>
<homePlace id="ref-4">湖北</homePlace>
</a1:MyObject>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
MyObject.xml文件也可以用記事本打開,它的內容如下:
view plaincopy to clipboardprint?
<?xml version="1.0"?>?
<MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">?
? <HomePlace>湖北</HomePlace>?
? <Birthday>1979-11-07T00:00:00</Birthday>?
? <Name>周公</Name>?
</MyObject>?
<?xml version="1.0"?>
<MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
? <HomePlace>湖北</HomePlace>
? <Birthday>1979-11-07T00:00:00</Birthday>
? <Name>周公</Name>
</MyObject>
熟悉SOAP協議的朋友一看MyObject.soap文件的內容就知道它符合SOAP協議,MyObject.xml文件毫無疑問是一個符合XML規范的文件。
對代碼作幾點說明:
1、如果采用BinaryFormatter類或者SoapFormatter類來實現序列化,則一定要給類加上Serializable屬性,如代碼中所示:
view plaincopy to clipboardprint?
[Serializable]??
??? /// <summary>??
??? /// 要序列化的對象??
??? /// 作者:周公??
??? /// 編寫時間:2009-03-10??
??? /// </summary>??
??? public class MyObject?
[Serializable]
??? /// <summary>
??? /// 要序列化的對象
??? /// 作者:周公
??? /// 編寫時間:2009-03-10
??? /// </summary>
??? public class MyObject
如果不給要序列化的對象加上這個屬性,那么采用采用BinaryFormatter類或者SoapFormatter類來實現序列化時會報異常,但使用XmlSerializer 類序列化對象時可以不用這個屬性。
2、另外,如果不想序列化某個字段,可以給其加上NonSerialized屬性,這樣在序列化時就不會保存這個這個字段的值了,比如不想序列化name這個字段,可以如下寫代碼:
view plaincopy to clipboardprint?
…//其它代碼??
//[NonSerialized]??
private string name;??
…//其它代碼?
…//其它代碼
//[NonSerialized]
private string name;
…//其它代碼
再次運行剛才的程序會得到如下效果:
?
看有黃色底線部分,因為name字段不被序列化,所以通過二進制序列化和SOAP序列化之后再反序化就得不到原來的值了。
3、最后還需要說明一點的是,SoapFormatter類在.net3.5開始已經過時了,微軟建議使用BinaryFormatter類來序列化和反序列化了。
周公
2009-03-11 0:17
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/zhoufoxcn/archive/2009/03/11/3978874.aspx