C#序列化與反序列化(Serializable and Deserialize)
序列化是指將對象實例的狀態存儲到存儲媒體的過程。在此過程中,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉換為字節流,然后再把字節流寫入數據流。在隨后對對象進行反序列化時,將創建出與原對象完全相同的副本。
我們經常需要將對象的字段值保存到磁盤中,并在以后檢索此數據。盡管不使用序列化也能完成這項工作,但這種方法通常很繁瑣而且容易出錯,并且在需要跟蹤對象的層次結構時,會變得越來越復雜。可以想象一下編寫包含大量對象的大型業務應用程序的情形,程序員不得不為每一個對象編寫代碼,以便將字段和屬性保存至磁盤以及從磁盤還原這些字段和屬性。序列化提供了輕松實現這個目標的快捷方法。
.NET公共語言運行時 (CLR) 管理對象在內存中的分布,.NET 框架則通過使用反射提供自動的序列化機制。對象序列化后,類的名稱、程序集以及類實例的所有數據成員均被寫入存儲媒體中。對象通常用成員變量來存儲對其他實例的引用。類序列化后,序列化引擎將跟蹤所有已序列化的引用對象,以確保同一對象不被序列化多次。.NET 框架所提供的序列化體系結構可以自動正確處理對象圖表和循環引用。對對象圖表的唯一要求是,由正在進行序列化的對象所引用的所有對象都必須標記為 Serializable(請參閱基本序列化)。否則,當序列化程序試圖序列化未標記的對象時將會出現異常。
當反序列化已序列化的類時,將重新創建該類,并自動還原所有數據成員的值。
在C#中常見的序列化的方法主要也有三個:BinaryFormatter、SoapFormatter、XML序列化。本文就通過一個小例子主要說說這三種方法的具體使用和異同點。
新建一個vs2008控制臺工程SerializableTest,添加一個Person類,加上[Serializable]使其可以被序列化
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SerializableTest { [Serializable] public class Person { public string Sno { get; set; } public string Name { get; set; } public string Sex { get; set; } public int Age { get; set; } public string DisplayInfo() { return "我的學號是:" +Sno+ "\n我的名字是:"+Name + "\n我的性別為:"+Sex+"\n我的年齡:"+Age+"\n"; } } }
一、BinaryFormatter序列化方式
1、序列化:新建一個Person對象me,然后將其序列化保存到文件personInfo.txt中]
var me = new Person { Sno = "200719", Name = "yuananyun", Sex="man", Age=22 }; //創建一個格式化程序的實例 IFormatter formatter = new BinaryFormatter(); //創建一個文件流 Stream stream = new FileStream("c:/personInfo.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); formatter.Serialize(stream, me); stream.Close();
執行以上代碼將創建一個personInfo.txt文件,它包含了me對象的程序集信息、類名和字段信息。
2、反序列化:從文件personInfo.txt中還原一個對象
//反序列化 Stream destream = new FileStream("c:/personInfo.txt", FileMode.Open, FileAccess.Read, FileShare.Read); var stillme = (Person)formatter.Deserialize(destream); stream.Close();
整個程序如下:
using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace SerializableTest { class Program { static void Main(string[] args) { //創建一個格式化程序的實例 IFormatter formatter = new BinaryFormatter(); Console.WriteLine("對象序列化開始……"); var me = new Person { Sno = "200719", Name = "yuananyun", Sex="man", Age=22 }; //創建一個文件流 Stream stream = new FileStream("c:/personInfo.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); formatter.Serialize(stream, me); stream.Close(); Console.WriteLine("序列化結束!\n"); Console.WriteLine("反序列化開始……"); //反序列化 Stream destream = new FileStream("c:/personInfo.txt", FileMode.Open, FileAccess.Read, FileShare.Read); var stillme = (Person)formatter.Deserialize(destream); stream.Close(); Console.WriteLine("反序列化結束,輸出對象信息……"); Console.WriteLine(stillme.DisplayInfo()); Console.ReadKey(); } } }
運行結果如下:
注意:反序列化還原對象時,并不會調用Person類的構造函數
二、SoapFormatter序列化方式
與BinaryFormatter序列化方式類似,只需要把IFormatter formatter = new BinaryFormatter()改成 IFormatter formatter = new SoapFormatter(),并且引用程序集System.Runtime.Serialization.Formatters.Soap.dll(.net自帶的)
using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Soap; namespace SerializableTest { class Program { static void Main(string[] args) { //創建一個格式化程序的實例 IFormatter formatter = new SoapFormatter(); Console.WriteLine("對象序列化開始……"); var me = new Person { Sno = "200719", Name = "yuananyun", Sex="man", Age=22 }; //創建一個文件流 Stream stream = new FileStream("c:/personInfo.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); formatter.Serialize(stream, me); stream.Close(); Console.WriteLine("序列化結束!\n"); Console.WriteLine("反序列化開始……"); //反序列化 Stream destream = new FileStream("c:/personInfo.txt", FileMode.Open, FileAccess.Read, FileShare.Read); var stillme = (Person)formatter.Deserialize(destream); stream.Close(); Console.WriteLine("反序列化結束,輸出對象信息……"); Console.WriteLine(stillme.DisplayInfo()); Console.ReadKey(); } } }
結果與第一種方式一樣。
序列化之后的文件是Soap格式的文件(簡單對象訪問協議(Simple Object Access Protocol,SOAP),是一種輕量的、簡單的、基于XML的協議,它被設計成在WEB上交換結構化的和固化的信息。 SOAP 可以和現存的許多因特網協議和格式結合使用,包括超文本傳輸協議(HTTP),簡單郵件傳輸協議(SMTP),多用途網際郵件擴充協議(MIME)。它還支持從消息系統到遠程過程調用(RPC)等大量的應用程序。SOAP使用基于XML的數據結構和超文本傳輸協議(HTTP)的組合定義了一個標準的方法來使用Internet上各種不同操作環境中的分布式對象。),其內容如下:
<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:Person id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SerializableTest/SerializableTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_x003C_Sno_x003E_k__BackingField id="ref-3">200719</_x003C_Sno_x003E_k__BackingField>
<_x003C_Name_x003E_k__BackingField id="ref-4">yuananyun</_x003C_Name_x003E_k__BackingField>
<_x003C_Sex_x003E_k__BackingField id="ref-5">man</_x003C_Sex_x003E_k__BackingField>
<_x003C_Age_x003E_k__BackingField>22</_x003C_Age_x003E_k__BackingField>
</a1:Person>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
三、XML序列化方式
using System; using System.IO; using System.Runtime.Serialization; using System.Xml.Serialization; namespace SerializableTest { class Program { static void Main(string[] args) { //創建一個格式化程序的實例 XmlSerializer formatter = new XmlSerializer(typeof(Person)); Console.WriteLine("對象序列化開始……"); var me = new Person { Sno = "200719", Name = "yuananyun", Sex="man", Age=22 }; //創建一個文件流 Stream stream = new FileStream("c:/personInfo.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); formatter.Serialize(stream, me); stream.Close(); Console.WriteLine("序列化結束!\n"); Console.WriteLine("反序列化開始……"); //反序列化 Stream destream = new FileStream("c:/personInfo.txt", FileMode.Open, FileAccess.Read, FileShare.Read); var stillme = (Person)formatter.Deserialize(destream); stream.Close(); Console.WriteLine("反序列化結束,輸出對象信息……"); Console.WriteLine(stillme.DisplayInfo()); Console.ReadKey(); } } }
結果與上述相同,xml序列化之后的文件就是一般的一個xml文件,personInfo.txt內容如下:
<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Sno>200719</Sno>
<Name>yuananyun</Name>
<Sex>man</Sex>
<Age>22</Age>
</Person>
注意:采用xml序列化的方式只能保存public的字段和可讀寫的屬性,對于private等類型的字段不能進行序列化
下面進行驗證
將Person的Name屬性改成Private,然后查看生成的personInfo.text,其內容如下:
<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Sno>200719</Sno>
<Sex>man</Sex>
<Age>22</Age>
</Person>
可以看到Name屬性并沒有出現在該文件中,反序列化生成的對象中Name屬性值為NULL。
以上對c#序列化和反序列化的三種方式進行了舉例說明。當然您也可以決定一個類中那些屬性序列化或不序列化,可以通過使用 NonSerialized 屬性標記成員變量來防止它們被序列化,具體內容請查閱相關資料。