序列化反序列化之C#

序列化和反序列化我们可能经常会听到,其实通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用。
序列化和反序列化最主要的作用有:
1
、在进程下次启动时读取上次保存的对象的信息
2
、在不同的AppDomain或进程之间传递数据
3
、在分布式应用系统中传递数据
......
C#中常见的序列化的方法主要也有三个:BinaryFormatterSoapFormatterXML序列化
本文就通过一个小例子主要说说这三种方法的具体使用和异同点

这个例子就是使用三种不同的方式把一个Book对象进行序列化和反序列化,当然这个Book类首先是可以被序列化的。
Book


CODE:

using System;
using System.Collections;
using System.Text;

namespace SerializableTest
{
    [Serializable]
    public class Book
    {
        public Book()
        {
            alBookReader = new ArrayList();
        }

        public string strBookName;

        [NonSerialized]
        public string strBookPwd;

        private string _bookID;
        public string BookID
        {
            get { return _bookID; }
            set { _bookID = value; }
        }

        public ArrayList alBookReader;

        private string _bookPrice;
        public void SetBookPrice(string price)
        {
            _bookPrice = price;
        }

        public void Write()
        {
            Console.WriteLine("Book ID:" + BookID);
            Console.WriteLine("Book Name:" + strBookName);
            Console.WriteLine("Book Password:" + strBookPwd);
            Console.WriteLine("Book Price:" + _bookPrice);
            Console.WriteLine("Book Reader:");
            for (int i = 0; i < alBookReader.Count; i++)
            {
                Console.WriteLine(alBookReader[i]);
            }
        }
    }
}





这个类比较简单,就是定义了一些public字段和一个可读写的属性,一个private字段,一个标记为[NonSerialized]的字段,具体会在下面的例子中体现出来

一、BinaryFormatter序列化方式
1
、序列化,就是给Book类赋值,然后进行序列化到一个文件中



CODE:

            Book book = new Book();
            book.BookID = "1";
            book.alBookReader.Add("gspring");
            book.alBookReader.Add("
永春");
            book.strBookName = "C#
强化";
            book.strBookPwd = "*****";
            book.SetBookPrice("50.00");
            BinarySerialize serialize = new BinarySerialize();
            serialize.Serialize(book);




2
、反序列化



CODE:

            BinarySerialize serialize = new BinarySerialize();
            Book book = serialize.DeSerialize();
            book.Write();




3
、测试用的
BinarySerialize


CODE:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace SerializableTest
{
    public class BinarySerialize
    {
        string strFile = "c:""book.data";

        public void Serialize(Book book)
        {
            using (FileStream fs = new FileStream(strFile, FileMode.Create))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(fs, book);
            }
        }

        public Book DeSerialize()
        {
            Book book;
            using (FileStream fs = new FileStream(strFile, FileMode.Open))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                book = (Book)formatter.Deserialize(fs);
            }
            return book;
        }
    }
}





主要就是调用System.Runtime.Serialization.Formatters.Binary空间下的BinaryFormatter类进行序列化和反序列化,以缩略型二进制格式写到一个文件中去,速度比较快,而且写入后的文件已二进制保存有一定的保密效果。
调用反序列化后的截图如下:

也就是说除了标记为NonSerialized的其他所有成员都能序列化

二、SoapFormatter序列化方式
调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看SoapSerialize
SoapSerialize


CODE:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;

namespace SerializableTest
{

    public class SoapSerialize
    {
        string strFile = "c:""book.soap";

        public void Serialize(Book book)
        {
            using (FileStream fs = new FileStream(strFile, FileMode.Create))
            {
                SoapFormatter formatter = new SoapFormatter();

                formatter.Serialize(fs, book);
            }
        }

        public Book DeSerialize()
        {
            Book book;
            using (FileStream fs = new FileStream(strFile, FileMode.Open))
            {
                SoapFormatter formatter = new SoapFormatter();
                book = (Book)formatter.Deserialize(fs);
            }
            return book;
        }
    }
}





主要就是调用System.Runtime.Serialization.Formatters.Soap空间下的SoapFormatter类进行序列化和反序列化,使用之前需要应用System.Runtime.Serialization.Formatters.Soap.dll.net自带的)
序列化之后的文件是Soap格式的文件(简单对象访问协议(Simple Object Access ProtocolSOAP),是一种轻量的、简单的、基于XML的协议,它被设计成在WEB上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议(HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还支持从消息系统到远程过程调用(RPC)等大量的应用程序。SOAP使用基于XML的数据结构和超文本传输协议(HTTP)的组合定义了一个标准的方法来使用Internet上各种不同操作环境中的分布式对象。)
调用反序列化之后的结果和方法一相同

三、XML序列化方式
调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看XmlSerialize
XmlSerialize


CODE:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace SerializableTest
{
    public class XmlSerialize
    {
        string strFile = "c:""book.xml";

        public void Serialize(Book book)
        {
            using (FileStream fs = new FileStream(strFile, FileMode.Create))
            {
                XmlSerializer formatter = new XmlSerializer(typeof(Book));
                formatter.Serialize(fs, book);
            }
        }

        public Book DeSerialize()
        {
            Book book;
            using (FileStream fs = new FileStream(strFile, FileMode.Open))
            {
                XmlSerializer formatter = new XmlSerializer(typeof(Book));
                book = (Book)formatter.Deserialize(fs);
            }
            return book;
        }
    }
}





从这三个测试类我们可以看出来其实三种方法的调用方式都差不多,只是具体使用的类不同
xml
序列化之后的文件就是一般的一个xml文件:
book.xml


CODE:

<?xml version="1.0"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <strBookName>C#
强化</strBookName>
 <strBookPwd>*****</strBookPwd>
 <alBookReader>
    <anyType xsi:type="xsd:string">gspring</anyType>
    <anyType xsi:type="xsd:string">
永春</anyType>
 </alBookReader>
 <BookID>1</BookID>
</Book>




输出截图如下:

也就是说采用xml序列化的方式只能保存public的字段和可读写的属性,对于private等类型的字段不能进行序列化

关于循环引用:
比如在上面的例子Book类中加入如下一个属性:
        public Book relationBook;
在调用序列化时使用如下方法:



CODE:

            Book book = new Book();
            book.BookID = "1";
            book.alBookReader.Add("gspring");
            book.alBookReader.Add("
永春");
            book.strBookName = "C#
强化";
            book.strBookPwd = "*****";
            book.SetBookPrice("50.00");

            Book book2 = new Book();
            book2.BookID = "2";
            book2.alBookReader.Add("gspring");
            book2.alBookReader.Add("
永春");
            book2.strBookName = ".NET
强化";
            book2.strBookPwd = "*****";
            book2.SetBookPrice("40.00");

            book.relationBook = book2;
            book2.relationBook = book;
            BinarySerialize serialize = new BinarySerialize();
            serialize.Serialize(book);



这样就会出现循环引用的情况,对于BinarySerializeSoapSerialize可以正常序列化(.NET内部进行处理了),对于XmlSerialize出现这种情况会报错:"序列化类型 SerializableTest.Book 的对象时检测到循环引用。"

C#序列化和反序列化程序都是基于工厂模式下的,那么C#序列化和反序列化到底有什么不同之处么?那么本文就向你详细介绍C#序列化和反序列化程序的区别及其应用。

C#序列化和反序列化,两者的程序处理方式基本一致,都是基于工厂模式的,所谓C#序列化就是是将对象转换为容易传输的格式的过程,一般情况下转化打流文件,放入内存或者IO文件中。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象,或者和其它应用程序共享使用。相反的,反序列化根据流重新构造对象。.NET自带的有两种序列化对象的方式,Xml和binary的,XML 序列化不转换方法、索引器、私有字段或只读属性(只读集合除外)。要序列化对象的所有字段和属性(公共的和私有的),请使用 BinaryFormatter,而不要使用 XML 序列化。

C#序列化和反序列化的实例应用剖析:

二进制的C#序列化的方式:

例如我们有个对象:

[Serializable]public class ClassToSerialize{  public int id=100;  public string name="Name";  }  需要序列化该对象,必须在给该类加上Serializable的属性,然后创建一个序列化写入的流:FileStream fileStream = new FileStream("temp.dat", FileMode.Create);然后创建二进制格式器:BinaryFormatter b=new BinaryFormatter();然后是序列化:b.Serialize(fileStream,c);,然后关闭保存流。(可以见下面的例子)

读取一个已经被序列化的对象的时候:操作方式一样,只是

FileStream fileStream = new FileStream(  "temp.dat", FileMode.Open,   FileAccess.Read, FileShare.Read);  ClassToSerialize c =  (ClassToSerialize)b.Deserialize(fileStream); 然后就可以读取了,完整的例子是:

using System;  using System.IO;  using System.Runtime.Serialization;  using System.Runtime.Serialization.Formatters.Binary;  public class SerialTest{  public void SerializeNow(){  ClassToSerialize c=new ClassToSerialize();  FileStream fileStream = new FileStream(  "temp.dat", FileMode.Create);   BinaryFormatter b=new BinaryFormatter();  b.Serialize(fileStream,c);  fileStream.Close();  }  public void DeSerializeNow(){  ClassToSerialize c=new ClassToSerialize();  FileStream fileStream = new FileStream(  "temp.dat", FileMode.Open,   FileAccess.Read,   FileShare.Read);  BinaryFormatter b=new BinaryFormatter();  //SoapFormatter  c=(ClassToSerialize)b.Deserialize(fileStream);  Console.WriteLine(c.name);  fileStream.Close();  }  public static void Main(string[] s){  SerialTest st=new SerialTest();  st.SerializeNow();  st.DeSerializeNow();  }  }  [Serializable]  public class ClassToSerialize{  public int id=100;  public string name="Name";  }  这就是自带的序列化和反序列的操作,但是,很多情况下,一个对象比较大,而且很多私有的属性和方法我们不需要,例如在原型模式里面序列化的话,只需要序列Clone方法和一些属性,私有的方法无需要,还例如在读取大规模的IO的时候,读取操作完全不需要... 这时候就需要自己集成重写序列的ISerializable接口:

实现该接口需要两个注意的,一个就是构造函数,主要是为了反序列,另一个就是GetObjectData,主要是执行序列化,例如我们现在有一个Employee类需要序列化

[Serializable()]  //Set this attribute to all the classes that want to serialize  public class Employee : ISerializable   //derive your class from ISerializable {  public int EmpId;  public string EmpName;  [NonSerialized()]  public string NoSerialString="NoSerialString-Test";   } 需要注意的是我这里的NoSerialString属性前面有[NonSerialized()],就是说默认并不序列化这个属性,而是使用默认值 。

首先是构造函数:

public Employee(SerializationInfo info, StreamingContext ctxt)  {  EmpId = (int)info.GetValue(  "EmployeeId", typeof(int));  EmpName = (String)info.GetValue(  "EmployeeName", typeof(string));  //NoSerialString =   //(String)info.GetValue("NoSerialString", typeof(string));  } 然后是C#序列化方法,就是当写入流的时候怎么保存的:

public void GetObjectData(SerializationInfo info, StreamingContext ctxt)  {  //You can use any custom name for your name-value pair.  // But make sure you  // read the values with the same name.  //For ex:- If you write EmpId as "EmployeeId"  // then you should read the same with "EmployeeId"  info.AddValue("EmployeeId", EmpId);  info.AddValue("EmployeeName", EmpName);  } 把上面两个方法写入到Employee类,然后写个测试的程序:

public class ObjSerial{  public static void Main(String[] args){  Employee mp = new Employee();  mp.EmpId = 10;  mp.EmpName = "Omkumar";  mp.NoSerialString = "你好啊";      //C#序列化和反序列化之序列化  Stream stream = File.Open("EmployeeInfo.osl", FileMode.Create);  BinaryFormatter bformatter = new BinaryFormatter();   Console.WriteLine("Writing Employee Information");  bformatter.Serialize(stream, mp);  stream.Close();    mp = null;     //C#序列化和反序列化之反序列  stream = File.Open("EmployeeInfo.osl", FileMode.Open);  bformatter = new BinaryFormatter();   Console.WriteLine("Reading Employee Information");  mp = (Employee)bformatter.Deserialize(stream);  stream.Close();   Console.WriteLine(  "Employee Id: {0}",mp.EmpId.ToString());  Console.WriteLine(  "Employee Name: {0}",mp.EmpName);  Console.WriteLine(  "Employee NoSerialString: {0}",mp.NoSerialString);   }  }  C#序列化和反序列化程序执行的结果是:

Writing Employee Information  Reading Employee Information  Employee Id: 10  Employee Name: Omkumar  Employee NoSerialString: NoSerialString-Test 看到Employee NoSerialString:属性的值没有,它保持默认值,没有序列化

前些天看到“序列化”这个概念,大意就是把对象保存为一个文件,下次再使用时,反序列化一下就OK了,第二天一大早到公司立马做了个Demo,哇,不错,非常之不错,使用此方法后,根本没有延迟的现象。今天终于应用到这个项目中了,同志们再也不用等那10秒了。

using System;  
using System.IO;  
using System.Windows.Forms;  
using System.Runtime.Serialization.Formatters.Binary;  
using System.Data;  
 
//from:http://www.ecjtu.org/forum/read.php?tid-12933.html  
//反序列化:SerializeTree.TreeViewDataAccess.LoadTreeViewData(treeView1,"C://treeview.txt");  
//序列化:  SerializeTree.TreeViewDataAccess.SaveTreeViewData(treeView1,"C://treeview.txt");  
 
 
namespace SerializeTree  
{  
    /// <summary>  
    /// TreeView串行化类  
    /// </summary>  
    public class TreeViewDataAccess  
    {  
        public TreeViewDataAccess() { }  
 
        /// <summary>  
        /// TreeViewData  
        /// </summary>  
        [Serializable()]  
        public struct TreeViewData  
        {  
            public TreeNodeData[] Nodes;  
 
            /// <summary>  
            /// 递归初始化TreeView数据  
            /// </summary>  
            /// <param name="treeview"></param>  
            public TreeViewData(TreeView treeview)  
            {  
                Nodes = new TreeNodeData[treeview.Nodes.Count];  
                if (treeview.Nodes.Count == 0)  
                {  
                    return;  
                }  
                for (int i = 0; i <= treeview.Nodes.Count - 1; i++)  
                {  
                    Nodes[i] = new TreeNodeData(treeview.Nodes[i]);  
                }  
            }  
 
            /// <summary>  
            /// 通过TreeViewData弹出TreeView  
            /// </summary>  
            /// <param name="treeview"></param>  
            public void PopulateTree(TreeView treeview)  
            {  
                if (this.Nodes == null || this.Nodes.Length == 0)  
                {  
                    return;  
                }  
                treeview.BeginUpdate();  
                for (int i = 0; i <= this.Nodes.Length - 1; i++)  
                {  
                    treeview.Nodes.Add(this.Nodes[i].ToTreeNode());  
                }  
                treeview.EndUpdate();  
            }  
        }  
 
        /// <summary>  
        /// TreeNodeData  
        /// </summary>  
        [Serializable()]  
        public struct TreeNodeData  
        {  
            public string Text;  
            public int ImageIndex;  
            public int SelectedImageIndex;  
            public bool Checked;  
            public bool Expanded;  
            public object Tag;  
            public TreeNodeData[] Nodes;  
 
            /// <summary>  
            /// TreeNode构造函数  
            /// </summary>  
            /// <param name="node"></param>  
            public TreeNodeData(TreeNode node)  
            {  
                this.Text = node.Text;  
                this.ImageIndex = node.ImageIndex;  
                this.SelectedImageIndex = node.SelectedImageIndex;  
                this.Checked = node.Checked;  
                this.Expanded = node.IsExpanded;  
                this.Nodes = new TreeNodeData[node.Nodes.Count];  
 
                if ((!(node.Tag == null)) && node.Tag.GetType().IsSerializable)  
                {  
                    this.Tag = node.Tag;  
                }  
                else 
                {  
                    this.Tag = null;  
                }  
                if (node.Nodes.Count == 0)  
                {  
                    return;  
                }  
                for (int i = 0; i <= node.Nodes.Count - 1; i++)  
                {  
                    Nodes[i] = new TreeNodeData(node.Nodes[i]);  
                }  
            }  
 
            /// <summary>  
            /// TreeNodeData返回TreeNode  
            /// </summary>  
            /// <returns></returns>  
            public TreeNode ToTreeNode()  
            {  
                TreeNode ToTreeNode = new TreeNode(this.Text, this.ImageIndex, this.SelectedImageIndex);  
                ToTreeNode.Checked = this.Checked;  
                ToTreeNode.Tag = this.Tag;  
                if (this.Expanded)  
                {  
                    ToTreeNode.Expand();  
                }  
                if (this.Nodes == null && this.Nodes.Length == 0)  
                {  
                    return null;  
                }  
                if (ToTreeNode != null && this.Nodes.Length == 0)  
                {  
                    return ToTreeNode;  
                }  
                for (int i = 0; i <= this.Nodes.Length - 1; i++)  
                {  
                    ToTreeNode.Nodes.Add(this.Nodes[i].ToTreeNode());  
                }  
                return ToTreeNode;  
            }  
        }  
        /// <summary>  
        /// 加载TreeView  
        /// </summary>  
        /// <param name="treeView"></param>  
        /// <param name="path"></param>  
        public static void LoadTreeViewData(TreeView treeView, string path)  
        {  
 
            BinaryFormatter ser = new BinaryFormatter();  
            Stream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);  
            TreeViewData treeData = ((TreeViewData)(ser.Deserialize(file)));  
            treeData.PopulateTree(treeView);  
            file.Close();  
 
        }  
 
        /// <summary>  
        /// 保存TreeView到文件  
        /// </summary>  
        /// <param name="treeView"></param>  
        /// <param name="path"></param>  
        public static void SaveTreeViewData(TreeView treeView, string path)  
        {  
            BinaryFormatter ser = new BinaryFormatter();  
            Stream file = new FileStream(path, FileMode.Create);  
            ser.Serialize(file, new TreeViewData(treeView));  
            file.Close();  
 
        }  
    }  
 
    //柳永法加的,序列化,及反序列化DataTable  
    class SerializeDataTable  
    {  
        public static DataTable LoadDataTable(string path)  
        {  
 
            BinaryFormatter ser = new BinaryFormatter();  
            Stream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);  
            DataTable dt = (DataTable)ser.Deserialize(file);  
            file.Close();  
            return dt;  
        }  
 
        public static void SaveDataTable(DataTable dt, string path)  
        {  
            BinaryFormatter ser = new BinaryFormatter();  
            Stream file = new FileStream(path, FileMode.Create);  
            ser.Serialize(file, dt);  
            file.Close();  
 
        }  
    }  
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值