XML的序列化和反序列化 詳細介紹


XML的序列化和反序列化 詳細介紹

為什么要做序列化和反序列化?

一個回答:

我們都知道對象是不能在網絡中直接傳輸的,不過還有補救的辦法。XML(Extensible Markup Language)可擴展標記語言,本身就被設計用來存儲數據,任何一個對象都可以用XML來描述。XML是可以作為對象信息的載體在網絡中傳輸,因為它是文本形式的。
怎么進行XML文檔與對象的相互轉換呢?
XmlSerializer類就是干這個活的。
命名空間:System.Xml.Serialization
程序集:System.Xml(在 system.xml.dll 中)
現在這里展示了一個提供序列化與反序列化方法的EncodeHelper類(在文章最后,並且會講解如何使用)。
Deserialize方法將XML字符串轉換為指定類型的對象;(反序列化)
Serialize方法則將對象轉換為XML字符串。(序列化)

另一個回答:

.Net程序執行時,對象都駐留在內存中;內存中的對象如果需要傳遞給其他系統使用;或者在關機時需要保存下來以便下次再次啟動程序使用就需要序列化和反序列化。
 
這兩個回答都是對的。
好了,現在我們來具體的看看XmlSerializer類的含義吧:
XmlSerializer類:將對象序列化到 XML 文檔中和從 XML 文檔中反序列化對象。 XmlSerializer 使您得以控制如何將對象編碼到 XML 中。
XML 序列化是將對象的公共屬性 (Property)(如Student的Name屬性)和字段轉換為序列格式(這里是指 XML)以便存儲或傳輸的過程。反序列化則是從 XML 輸出中重新創建原始狀態的對象。因此,可以將序列化視為將對象的狀態保存到流或緩沖區的方法。例如,ASP.NET 使用  XmlSerializer 類對 XML Web services 消息進行編碼。
 
范圍:本文只介紹xml序列化,其實序列化可以是二進制的序列化,也可以是其他格式的序列化
 
看一段最簡單的Xml序列化代碼
復制代碼
復制代碼
class Program
{
    static void Main(string[] args)
    {
        int i = 10;
        //聲明Xml序列化對象實例serializer
        XmlSerializer serializer = new XmlSerializer(typeof(int));
        //執行序列化並將序列化結果輸出到控制台
        serializer.Serialize(Console.Out, i);
        Console.Read();
    }
}
復制代碼
復制代碼

上面代碼對int i進行了序列化,並將序列化的結果輸出到了控制台,輸出結果如下:

<?xml version="1.0" encoding="gb2312"?>
<int>10</int>

可以將上述序列化的xml進行反序列化,如下代碼:

復制代碼
復制代碼
static void Main(string[] args)
{
    using (StringReader rdr = new StringReader(@"<?xml version=""1.0"" encoding=""gb2312""?>
<int>10</int>"))
    {
        //聲明序列化對象實例serializer 
        XmlSerializer serializer = new XmlSerializer(typeof(int));
        //反序列化,並將反序列化結果值賦給變量i
        int i = (int)serializer.Deserialize(rdr);
        //輸出反序列化結果
        Console.WriteLine("i = " + i);
        Console.Read();
    }
}
復制代碼
復制代碼

以上代碼用最簡單的方式說明了xml序列化和反序列化的過程,.Net系統類庫為我們做了大量的工作,序列化和反序列化都非常簡單。但是在現實中業務需求往往比較復雜,不可能只簡單的序列化一個int變量,顯示中我們需要對復雜類型進行可控制的序列化。

[XmlRoot("cat")]
/
/要求不序列化Speed屬性
[XmlIgnore]
[XmlAttribute]
[XmlElement]

可以使用XmlElement指定屬性序列化為子節點(默認情況會序列化為子節點);或者使用XmlAttribute特性制定屬性序列化為Xml節點的屬性;還可以通過XmlIgnore特性修飾要求序列化程序不序列化修飾屬性。

一、序列化對象

首先我們先定義實體類:

復制代碼
復制代碼
  public class People
    {
        //XmlAttribute:指定XmlSerializer將該類成員序列化為XML屬性
        [XmlAttribute]
        public string Name { get; set; }
        [XmlAttribute]
        public int Age { get; set; }
    }

    [XmlRoot]
    public class Student : People
    {
  
//定義SClass屬性的序列化為Student節點的屬性
[XmlElement] public string SClass { get; set; } [XmlElement] public int Number { get; set; } }
復制代碼
復制代碼

第一步:將實體類序列化為XML文檔,代碼如下:

    Student stu = new Student() { Age = 12, Number = 23, Name = "張三", SClass = "高一(2)班" };
    XmlSerializer ser = new XmlSerializer(typeof(Student));
    StringWriter writer = new StringWriter();
    ser.Serialize(writer,stu);
    MessageBox.Show(writer.ToString());

在彈出框,出現的結果是:

這樣,我們就序列化成功了啊。。
第二步:現在我們來進行反序列化測試:

    //將Xml反序列為Student對象
    StringReader reader = new StringReader(writer.ToString());
    //Deserialize反序列化指定TextReader包含的Xml文檔,當然,不僅僅可以是TextReader,還可以是Stream等等,具體看起構造函數參數即可知道
    Student stu2= (Student)ser.Deserialize(reader);

我們用上面得到XML數據進行反序列化測試。查看運行結果,ok的啦!

二、序列化列表
和上面一樣,序列化學生列表(People類和Student類和上面代碼一樣)

 

復制代碼
復制代碼
    List<Student> stuList = new List<Student>();
    stuList.Add(new Student() { Age = 10, Number = 1, Name = "Tom", SClass = "Class One" });
    stuList.Add(new Student() { Age = 11, Number = 2, Name = "Jay", SClass = "Class Two" });
    stuList.Add(new Student() { Age = 12, Number = 3, Name = "Pet", SClass = "Class One" });
    stuList.Add(new Student() { Age = 13, Number = 4, Name = "May", SClass = "Class Three" });
    stuList.Add(new Student() { Age = 14, Number = 5, Name = "Soy", SClass = "Class Two" });


     //序列化
    XmlSerializer ser = new XmlSerializer(typeof(List<Student>));
    StringWriter writer = new StringWriter();
    //將學生列表序列化為Xml數據
    ser.Serialize(writer, stuList);

    //反序列化
    //要先將構造StringReader,作為Deserialize()的初始化參數
    StringReader reader = new StringReader(writer.ToString());
    //別忘了從Object到List<Student>,否則會報錯。。
    List<Student> stuList2 = (List<Student>)ser.Deserialize(reader);
復制代碼
復制代碼

運行結果是(注意:根是ArrayOfStudent不是Student了):

 

三、序列化字典(鍵/值對)

在XmlSerializer中,不支持Dirctionary<>類型的對象,所以在序列化這種最常見類型的時候,只能按照它的格式先創建一個可以序列化的類型,然后,將數據存儲在該可序列化的類型中,然后再進行序列化即可。

復制代碼
復制代碼
    Dictionary<string, int> dic = new Dictionary<string, int>();
    dic.Add("第一",1);
    dic.Add("第二", 2);
    dic.Add("第三", 3);
    dic.Add("第四", 4);

    List<DictionaryList> dicList = new List<DictionaryList>();
    foreach (var a in dic)
    {
      DictionaryList dicl = new DictionaryList() {  Name=a.Key, Value=a.Value};
      dicList.Add(dicl);
       
    }
    //序列化
    XmlSerializer ser = new XmlSerializer(typeof(List<DictionaryList>));
    StringWriter writer = new StringWriter();
    //序列化為Xml數據
    ser.Serialize(writer, dicList);
    MessageBox.Show(writer.ToString());

    //反序列化
    StringReader reader = new StringReader(writer.ToString());            
    List<DictionaryList> stuList2 = (List<DictionaryList>)ser.Deserialize(reader);
復制代碼
復制代碼

運行結果是:

四、序列化圖片

 

 

 

 

 

 補充:XmlArray和XmlArrayItem的使用,用在數組中

 先構造實體類:

復制代碼
復制代碼
    [XmlRoot("cats")]
    public class CatCollection
    {
        [XmlArray("items"), XmlArrayItem("item")]
        public Cat[] Cats { get; set; }
    }

    //[XmlRoot("cat")] 加不加都無所謂的。
    public class Cat
    {
        //定義Color屬性的序列化為cat節點的屬性
        [XmlAttribute("color")]
        public string Color { get; set; }

        //要求不序列化Speed屬性
        [XmlIgnore]
        public int Speed { get; set; }

        //設置Saying屬性序列化為Xml子元素
        [XmlElement("saying")]
        public string Saying { get; set; }
    }
復制代碼
復制代碼

 現在,進行序列化:

復制代碼
復制代碼
   //聲明一個貓咪對象
   var cWhite = new Cat { Color = "White", Speed = 10, Saying = "White or black,  so long as the cat can catch mice,  it is a good cat" };
   var cBlack = new Cat { Color = "Black", Speed = 10, Saying = "White or black,  so long as the cat can catch mice,  it is a good cat" };

   CatCollection cc = new CatCollection { Cats = new Cat[] { cWhite, cBlack } };

   //序列化這個對象
   XmlSerializer serializer = new XmlSerializer(typeof(CatCollection));
   StringWriter writer = new StringWriter();
   serializer.Serialize(writer,cc);
   MessageBox.Show(writer.ToString());
復制代碼
復制代碼

運行結果是:

XmlSerializer內存泄漏問題:

多謝chenlulouis,仔細看了下msdn,確實存在泄漏的情況,msdn說明如下:

動態生成的程序集
為了提高性能,XML 序列化基礎結構將動態生成程序集,以序列化和反序列化指定類型。此基礎結構將查找並重復使用這些程序集。此行為僅在使用以下構造函數時發生:
XmlSerializer(Type)   XmlSerializer.XmlSerializer(Type, String)
如果使用任何其他構造函數,則會生成同一程序集的多個版本,且絕不會被卸載,這將導致內存泄漏和性能降低。最簡單的解決方案是使用先前提到的兩個構造函數的其中一個。否則,必須在 Hashtable 中緩存程序集,如以下示例中所示。

也就是說我們在使用XmlSerializer序列化,初始化XmlSerializer對象時最好使用下面兩個構造函數否則會引起內存泄漏。

XmlSerializer(Type)  XmlSerializer.XmlSerializer(Type, String)

C#處理Xml的相關隨筆:

補充:EncodeHelper類,只不過將上述我們序列化和反序列化進行封裝而已,很容易理解
復制代碼
復制代碼
/// <summary>
    /// 提供xml文檔序列化 反序列化
    /// </summary>
    public sealed class EncodeHelper
    {
        /// <summary>
        /// 反序列化XML字符串為指定類型
        /// </summary>
        public static object Deserialize(string Xml, Type ThisType)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(ThisType);
            object result;
            try
            {
                using (StringReader stringReader = new StringReader(Xml))
                {
                    result = xmlSerializer.Deserialize(stringReader);
                }
            }
            catch (Exception innerException)
            {
                bool flag = false;
                if (Xml != null)
                {
                    if (Xml.StartsWith(Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble())))
                    {
                        flag = true;
                    }
                }
                throw new ApplicationException(string.Format("Couldn't parse XML: '{0}'; Contains BOM: {1}; Type: {2}.", 
                Xml, flag, ThisType.FullName), innerException);
            }
            return result;
        }

        /// <summary>
        /// 序列化object對象為XML字符串
        /// </summary>
        public static string Serialize(object ObjectToSerialize)
        {
            string result = null ;
            try
            {
            XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());
            
            using (MemoryStream memoryStream = new MemoryStream())
            {
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(false));
                xmlTextWriter.Formatting = Formatting.Indented;
                xmlSerializer.Serialize(xmlTextWriter, ObjectToSerialize);
                xmlTextWriter.Flush();
                xmlTextWriter.Close();
                UTF8Encoding uTF8Encoding = new UTF8Encoding(false, true);
                result= uTF8Encoding.GetString(memoryStream.ToArray());
            }
            }
            catch (Exception innerException)
            {
                throw new ApplicationException("Couldn't Serialize Object:" + ObjectToSerialize.GetType().Name, innerException);
            }
            return result;
        }
    }
復制代碼
復制代碼

 

原文鏈接:https://www.cnblogs.com/itjeff/p/4262547.html

       http://hi.baidu.com/jackeyrain/item/79ad923564fa94f1e6bb7a11

     http://www.cnblogs.com/John-Connor/archive/2012/04/12/2440352.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM