序列化 (1) - 概述

  • 1811
  • 0
  • 2013-07-29

序列化(Serialization)是將物件轉換為可儲存或可傳輸特定格式的動作,還原序列化則是將分解後的特定格式轉換成物件,透過序列化與還原序列化,可使資料容易儲存和傳輸。

 

MSDN 技術文章:序列化 (1) - 概述

 

簡介

序列化(Serialization)是將物件轉換為可儲存或可傳輸特定格式的動作,還原序列化則是將分解後的特定格式轉換成物件,透過序列化與還原序列化,可使資料容易儲存和傳輸。

 

序列化類別

.NET Framework 提供兩種序列化技術:二進位序列化(Binary Serialization)和 XML 序列化(XML Serialization)。

  • 二進位序列化
    二進位序列化將物件序列化為二進位格式,此類型的序列化保留型別精確度,當物件被二進位序列化分解後,可以被傳送到特定儲存媒介,例如磁碟、記憶體和在網路上序列化等。
  • XML 序列化
    XML 序列化則是將物件序列化為 XML 物件,以 SOAP 進行存取,與二進位序列化不同之處在於 XML 序列化只序列化公用屬性和欄位內容,而不保留型別精確度,適用於您要提供或取用資料,而不限制使用該資料的應用程式時,例如跨網路傳送。

針對這兩種序列化技術,.NET Framework 提供對應的類別:BinaryFormatter 類別SoapFormatter 類別

  • BinaryFormatter 類別
    位於命名空間 System.Runtime.Serialization.Formatters.Binary 中,將物件進行二進位序列化分解,以及將分解後的物件做還原,其序列化 Serialize 方法的定義為:
public void Serialize(
            Stream serializationStream,
            Object graph
        )

此方法傳入 Stream 資料流物件和 Object 型別物件參數,將 Object 型別物件 graph 序列化後到第一個參數資料流物件中;還原序列化 Deserialize 方法的定義為:

public Object Deserialize(
            Stream serializationStream
 		)

 此方法傳入 Stream 資料流型別參數,即是將資料流物件重新還原為被序列化的物件。

  • SoapFormatter 類別
    位於命名空間 System.Runtime.Serialization.Formatters.Soap 中,此類別序列化和還原序列化的方法 SerializeDeserialize,其接受與回傳的參數與 BinaryFormatter 類別相同。

當你想要將類別的實體物件序列化和還原序列換之前,必須先判斷類別是否能序列化,通常是藉由屬性 <Serializable> 做標示,接著我們舉一個例子示範序列化與還原序列化的操作。

 

範例說明

範例程式表單畫面如下圖所示,可選擇使用二進位或 SOAP 進行序列化與還原序列化動作,並且將序列化與還原序列化的結果顯示在表單中。

程式碼的部分,首先建立一個類別,加上 <Serializable> 屬性標示為可序列化。 

[Serializable]
    public class ClsSerializable
    {
        private int _Number;
        private string _Name;
        private string _Cmt;
        public ClsSerializable()
        {
            this._Number = 7;
            this._Name = "Ou";
            this._Cmt = "喜歡音樂";
        }

        public int Number
        {
            get { return this._Number; }
        }
        public string Name
        {
            get { return this._Name; }
        }
        public string Cmt
        {
            get { return this._Cmt; }
        }
    }

建立一個方法 SerializeBinary(),使用 BinaryFormatter 類別的 Serialize 方法,傳入 ClsSerializable 類別物件來做二進位序列化,並寫入指定的檔案資料流中。

/// 
        /// 使用 BinaryFormatter 進行序列化
        /// 
        private void SerializeBinary()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = new ClsSerializable();
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write))
            {
                // 建立 BinaryFormatter 物件
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                // 將物件進行二進位序列化,並且儲存檔案
                binaryFormatter.Serialize(fileStream, clsSerializable);
            }
            // 將序列化後的檔案內容呈現到表單畫面
            StringBuilder sbContent = new StringBuilder();
            foreach (var byteData in File.ReadAllBytes(FileName))
            {
                sbContent.Append(byteData);
                sbContent.Append(" ");
            }
            this.rtbContent.Text = sbContent.ToString();
        }

 

 

另外我們建立一個方法 SerializeSoap(),將ClsSerializable 類別物件透過SoapFormatter 類別的 Serialize 方法做 XML 序列化,並且儲存到指定檔案中。我們可以發現 BinaryFormatter 和 SoapFormatter 類別的序列化使用方法相同。

/// 
        /// 使用 SoapFormatter 進行序列化
        /// 
        private void SerializeSoap()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = new ClsSerializable();
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write))
            {
                // 建立 SoapFormatter 物件
                SoapFormatter soapFormatter = new SoapFormatter();
                // 將物件進行 SOAP 序列化,並且儲存檔案
                soapFormatter.Serialize(fileStream, clsSerializable);
            }
            // 將序列化後的檔案內容呈現到表單畫面
            rtbContent.Text = File.ReadAllText(FileName);
        }

 

 針對二進制還原序列化的部分,建立方法 DeserializeBinary(),先做讀取檔案資料流的動作,透過 BinaryFormatter 類別的 Deserialize 方法還原序列化為 Object 物件,需要進一步做強制轉型成為正確的型別 ClsSerializable。

/// 
        /// 使用 BinaryFormatter 進行還原序列化
        /// 
        /// 
        private ClsSerializable DeserializeBinary()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = null;
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Open))
            {
                // 建立 BinaryFormatter 物件
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                // 將檔案內容還原序列化成 Object 物件,並且進一步轉型成正確的型別 ClsSerializable
                clsSerializable = (ClsSerializable)binaryFormatter.Deserialize(fileStream);
            }
            return clsSerializable;
        }

 

針對 XML 還原序列化的部分,建立方法 DeserializeSoap(),先讀取檔案內容,透過 SoapFormatter 類別的 Deserialize 方法還原序列化為 Object 物件,需要進一步做強制轉型成為正確的型別 ClsSerializable。我們可以發現 BinaryFormatter 和 SoapFormatter 類別的還原序列化的使用方法相同。

/// 
        /// 使用 SoapFormatter 進行還原序列化
        /// 
        /// 
        private ClsSerializable DeserializeSoap()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = null;
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Open))
            {
                // 建立 SoapFormatter 物件
                SoapFormatter soapFormatter = new SoapFormatter();
                // 將檔案內容還原序列化成 Object 物件,並且進一步轉型成正確的型別 ClsSerializable
                clsSerializable = (ClsSerializable)soapFormatter.Deserialize(fileStream);
            }
            return clsSerializable;
        }

 

完整的程式碼如下所示:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Text;
using System.Windows.Forms;

namespace WinFormsFormatter
{
    public partial class Form1 : Form
    {
        /// 
        /// 序列化檔案名稱
        /// 
        string FileName = string.Format(@"{0}\{1}", Application.StartupPath,"demo.txt");

        public Form1()
        {
            InitializeComponent();
        }

        #region 按鈕事件
        private void btnSerialize_Click(object sender, EventArgs e)
        {
            if (rbBinary.Checked == true)
            {
                SerializeBinary();
            }
            else
            {
                SerializeSoap();
            }
        }

        private void btnDeserialize_Click(object sender, EventArgs e)
        {
            ClsSerializable clsSerializable = null;
            if (rbBinary.Checked)
            {
                clsSerializable = DeserializeBinary();
            }
            else
            {
                clsSerializable = DeserializeSoap();
            }

            // 顯示還原序列化後的類別物件於畫面中
            string strContect = string.Format("Number: {0}\nName: {1}\nCmt: {2}", clsSerializable.Number, clsSerializable.Name, clsSerializable.Cmt);
        }
        #endregion

        #region BinaryFormatter
        /// 
        /// 使用 BinaryFormatter 進行序列化
        /// 
        private void SerializeBinary()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = new ClsSerializable();
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write))
            {
                // 建立 BinaryFormatter 物件
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                // 將物件進行二進位序列化,並且儲存檔案
                binaryFormatter.Serialize(fileStream, clsSerializable);
            }
            // 將序列化後的檔案內容呈現到表單畫面
            StringBuilder sbContent = new StringBuilder();
            foreach (var byteData in File.ReadAllBytes(FileName))
            {
                sbContent.Append(byteData);
                sbContent.Append(" ");
            }
            this.rtbContent.Text = sbContent.ToString();
        }

        /// 
        /// 使用 BinaryFormatter 進行還原序列化
        /// 
        /// 
        private ClsSerializable DeserializeBinary()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = null;
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Open))
            {
                // 建立 BinaryFormatter 物件
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                // 將檔案內容還原序列化成 Object 物件,並且進一步轉型成正確的型別 ClsSerializable
                clsSerializable = (ClsSerializable)binaryFormatter.Deserialize(fileStream);
            }
            return clsSerializable;
        }
        #endregion

        #region SoapFormatter
        /// 
        /// 使用 SoapFormatter 進行序列化
        /// 
        private void SerializeSoap()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = new ClsSerializable();
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write))
            {
                // 建立 SoapFormatter 物件
                SoapFormatter soapFormatter = new SoapFormatter();
                // 將物件進行 SOAP 序列化,並且儲存檔案
                soapFormatter.Serialize(fileStream, clsSerializable);
            }
            // 將序列化後的檔案內容呈現到表單畫面
            rtbContent.Text = File.ReadAllText(FileName);
        }

        /// 
        /// 使用 SoapFormatter 進行還原序列化
        /// 
        /// 
        private ClsSerializable DeserializeSoap()
        {
            // 建立 ClsSerializable 類別物件
            ClsSerializable clsSerializable = null;
            // 建立檔案資料流物件
            using (FileStream fileStream = new FileStream(FileName, FileMode.Open))
            {
                // 建立 SoapFormatter 物件
                SoapFormatter soapFormatter = new SoapFormatter();
                // 將檔案內容還原序列化成 Object 物件,並且進一步轉型成正確的型別 ClsSerializable
                clsSerializable = (ClsSerializable)soapFormatter.Deserialize(fileStream);
            }
            return clsSerializable;
        }
        #endregion

        [Serializable]
        public class ClsSerializable
        {
            private int _Number;
            private string _Name;
            private string _Cmt;
            public ClsSerializable()
            {
                this._Number = 7;
                this._Name = "Ou";
                this._Cmt = "喜歡音樂";
            }

            public int Number
            {
                get { return this._Number; }
            }
            public string Name
            {
                get { return this._Name; }
            }
            public string Cmt
            {
                get { return this._Cmt; }
            }
        }
    }
}

當程式執行時,選擇二進制選項,按下序列化按鈕,我們可以看到序列化後的二進制資料。

 

還原序列化後的結果如下圖示。

 

選擇SOAP選項,按下序列化按鈕,我們可以看到序列化後的 XML 資料。 

 

還原序列化後的結果如下圖示。

 

結語

本文說明了序列化技術和 .NET Framework 提供的序列化類別,並透過範例程式實作序列化與還原序列化,在沒有特殊考量的情況下,序列化與還原序列化的過程相當簡單,在接下來的系列文章中,將會說明在特殊狀況下較為彈性的作法。

 

其他相關資訊

序列化