谈谈序列化和反序列化的感触(TreeView序列化)

1 篇文章 0 订阅
1 篇文章 0 订阅
1.对于C#理解不深,对于序列化Serialize和反序列化Deserialize更是颇有微词。
对于我这样一个半路的业余爱好者,我想,我只需要方便和实现我需要的功能,但微软咋就做的不那么方便的呢?我想序列化就是能实现一个对象,一个控件的参数可以直接存成文件(即序列化),用反序列化即可反向构建这个对象和控件参数,属性值等。
比如,我就需要界面上的TreeView1(有很多子节点)序列化直接存为文件,反序列化即可一下子,将其内存copy到另外一个TreeView2上构建出相同的对象。这样,就是导入导出参数功能的了。放大,则是整个UI界面,可序列化的控件标识一下,序列化为文件,反序列化的时候就一下构建出各个可序列化的控件,不能构建的,则空白即可。
但,比较遗憾的是,至少没有这么直观的方法,不晓得微软咋想的,安全性原因?!不深入讨论这个问题了,说说别的。

2.Bin序列化和xml序列化:
1).以前,总想用个可以找个能读取Bin文件的工具,我就能看见里面的序列化对象名称和参数值的了,但很遗憾,费了很多心思也没有,结果查到的消息就是微软不想让你看见内容的。Bin序列化优点就是方便,非明文,安全性高,什么internal,private之类的字段都能序列化。
2).XML序列化则是可以看见明文,这样,若增加了字段,以前保存的参数文件,至少我能明文看见怎么参数值的,可手动再设置一遍。缺点是字段都必须是public属性才能xml序列化。

3.对于常常用到的TreeView不能直接序列化,比较愤恨,一大堆子节点,不小心就弄错的。而且,不想学仔细研究一行行去序列化各个字段,太繁琐。所以,百度一些方法,整理了一下,找了一个解决办法。

1.TreeViewDataAccess.cs(150703)

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

using System.Data;

//
//v1.1  2015-7-03
//


namespace SerializerTool
{
    public class TreeViewAdvanced
    {
        public TreeViewAdvanced() { }  //删除也可以的

        /// TreeViewData
        [Serializable()]
        public struct TreeViewSt
        {
            public TreeNodeData[] Nodes;

            /// 递归初始化TreeView数据
            public TreeViewSt(TreeView tv)
            {
                Nodes = new TreeNodeData[tv.Nodes.Count];
                if (tv.Nodes.Count == 0) return;
                for (int i = 0; i <= tv.Nodes.Count - 1; i++)
                {
                    Nodes[i] = new TreeNodeData(tv.Nodes[i]);
                }
            }

            /// 通过TreeViewSt弹出TreeView

            public void PopulateTree(TreeView tv)
            {
                if (this.Nodes == null || this.Nodes.Length == 0) return;

                tv.BeginUpdate();
                for (int i = 0; i <= this.Nodes.Length - 1; i++)
                {
                    tv.Nodes.Add(this.Nodes[i].ToTreeNode());
                }
                tv.EndUpdate();
            }
        }


        /// TreeNodeData
        [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;

            /// TreeNode构造函数
            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]);
                }
            }

            /// TreeNodeData返回TreeNode

            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;
            }
        }

        /// 加载TreeView
        public static void LoadTreeViewData(TreeView tv, string path)
        {
            BinaryFormatter ser = new BinaryFormatter();
            Stream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            TreeViewSt treeData = ((TreeViewSt)(ser.Deserialize(file)));
            treeData.PopulateTree(tv);
            file.Close();
        }

        /// 保存TreeView到文件
        public static void SaveTreeViewData(TreeView tv, string path)
        {
            BinaryFormatter ser = new BinaryFormatter();
            Stream file = new FileStream(path, FileMode.Create);
            ser.Serialize(file, new TreeViewSt(tv));
            file.Close();
        }
    }

    //柳永法加的,序列化/反序列化DataTable
    class SerializeDataTable
    {
        public static DataTable LoadDataTable(string path)
        {
            BinaryFormatter bf = new BinaryFormatter();
            Stream sm = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);

            DataTable dt = (DataTable)bf.Deserialize(sm);
            sm.Close();
            return dt;
        }

        public static void SaveDataTable(DataTable dt, string path)
        {
            BinaryFormatter bf = new BinaryFormatter();
            Stream sm = new FileStream(path, FileMode.Create);
            bf.Serialize(sm, dt);
            sm.Close();
        }
    }
}


2.BinarySerializer.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
namespace SerializerTool
{
    [Serializable]
    public class BinarySerializer
    {
        public static void Serialize<T>(T o,string filePath)
        {
            try 
            {
                BinaryFormatter formatter = new BinaryFormatter();
                Stream sm = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
                formatter.Serialize(sm, o);
                sm.Flush();
                sm.Close();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public static T DeSerialize<T>(string filePath)
        {
            try
            {
                BinaryFormatter formatter = new BinaryFormatter();
                Stream sm = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                T o = (T)formatter.Deserialize(sm);
                sm.Flush();
                sm.Close();
                return o;
            }
            catch (Exception)
            {
                
            }
            return default(T);
        }
    }
}


3.XmlSerializer.cs

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

namespace SerializerTool
{
    [Serializable]
    public class XMLSerializer
    {
        public static void Serialize<T>(T o,string filePath)
        {
            try 
            {
                XmlSerializer formatter = new XmlSerializer(typeof(T));
                StreamWriter sw = new StreamWriter(filePath, false);
                formatter.Serialize(sw,o);
                sw.Flush();
                sw.Close();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public static T DeSerialize<T>(string filePath)
        {
            try
            {
                XmlSerializer formatter = new XmlSerializer(typeof(T));
                StreamReader sr = new StreamReader(filePath);
                T o = (T)formatter.Deserialize(sr);
                sr.Close();
                return o;
            }
            catch (Exception)
            {
                
            }
            return default(T);
        }
    }
}

4.使用方法,放2个多节点的treeview,以xml序列化和反序列化为例(bin同理):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using SerializerTool;

namespace SerializerTool
{
    [Serializable]
    public struct TVSt
    {
        public TreeViewAdvanced.TreeViewSt inTV;  //对应treeview1
        public TreeViewAdvanced.TreeViewSt outTV;  //对应treeview2</span></p><p><span style="color:#3333FF;">     }</span></p><p>.....................................</p><p>        private void button11_Click(object sender, EventArgs e)    //xml序列化方法
        {
            TVSt myTv = new TVSt();
            myTv.inTV = new TreeViewAdvanced.TreeViewSt(treeView1);
            myTv.outTV = new TreeViewAdvanced.TreeViewSt(treeView2);
            XMLSerializer.Serialize(myTv, "mytv.xml");

        }

        private void button13_Click(object sender, EventArgs e)   //xml反序列化方法,此例实现的是对调2个treeview内容的演示
        {
            treeView1.Nodes.Clear();
            treeView2.Nodes.Clear();   
        
            TVSt myTv;
            myTv = XMLSerializer.DeSerialize<TVSt>("mytv.xml");   //反序列化,得到包含多个treeview的结构体

           
            myTv.inTV.PopulateTree(treeView2);    //还原结构体内容,需要指定对应关系
            myTv.outTV.PopulateTree(treeView1);   //同上
        }
}

总之,若界面上的一些控件或者一些参数,需要放到一个结构体之内,然后对此定义的结构体进行序列化和反序列化,才可以实现我们所想要的导入导出参数功能。

为了防止忘记,note一下:

XmlSerializer 对象的Xml序列化和反序列化

[Serializable]                                                         ------后面的内容可序列化的类或者结构体(含多个字段)

[NonSerialized]                                                     ------   用于Bin序列化中,不序列化的字段前加一个这个,序列化时就不输出其内容
[System.Xml.Serialization.XmlIgnoreAttribute] ----    类似于NonSerialized, xml序列化时,不输出其指定字段的内容

网上,这些不是经常提到的。

2015.07.04  北京


新提示:若xml文件中有类似以下字符的,会被中断而xml反序列化不成功的哈!反正是不支持,这个花了我好多天才发现问题所在的地方的,好累眼睛!&#x0;代表byte中的0;

<prgName>www&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;&#x0;</prgName>

产生原因:string和byte[]之间转换造成

之前使用的userPrgInfo.prgName = Encoding.GetEncoding("gbk").GetString(prg.ts.programName);
变为userPrgInfo.prgName = Encoding.GetEncoding("gbk").GetString(prg.ts.programName).TrimEnd('\0');即可解决。


网上有朋友有别的方法,如下:

如果反序列化时未给这种&#xE;做特殊处理,反序列化将失败,如果xml中包含有未编码的低位字符,XmlDocument对象将报错;

替换掉未编码的低位序列字符,例如替换掉:

 

   public static string Repalce(string str)
        {
            return System.Text.RegularExpressions.Regex.Replace(str, @"[\x00-\x08]|[\x0B-\x0C]|[\x0E-\x1F]", "");
        }


替换后xml正常加载


8:28 2015-8-5


5.XmlSerializer.cs的扩展,允许多种类型

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

using Shawn.WL.WanLongPannel.Dll;
//using Shawn.WL.WanLongPannel.devs;


namespace KTools.Serializer
{
    [Serializable]
    public class XMLSerializer
    {
        public static Type[] extraTypes;  //添加可能使用到的类型
        public static void SetTpyes()
        {
            extraTypes = new Type[26];
            extraTypes[0] = typeof(System.Collections.ArrayList);
            extraTypes[1] = typeof(AcItemSt_v1);
            extraTypes[2] = typeof(AcItemSt_v2);
            extraTypes[3] = typeof(AcItemSt_v3);
            extraTypes[4] = typeof(CA_descriptor);
            extraTypes[5] = typeof(CaRuleSt_item);
            extraTypes[6] = typeof(CasFlagSt);
            extraTypes[7] = typeof(CasSt);
            extraTypes[8] = typeof(ChannelProgramSt);
            extraTypes[9] = typeof(Chn_ca_st);
            extraTypes[10] = typeof(Commdes_st);
            extraTypes[11] = typeof(DataStream_st);
            extraTypes[12] = typeof(DataStream_st);
            extraTypes[13] = typeof(Dev_prgInfo_st);
            extraTypes[14] = typeof(EncoderPartStFstV2);
            extraTypes[15] = typeof(MuxDbSaveSt);
            extraTypes[16] = typeof(MuxPidInfo_st);
            extraTypes[17] = typeof(MuxPrgInfoGet_st);
            extraTypes[18] = typeof(Nit_section_st);
            extraTypes[19] = typeof(ScramblePidSt_v2);
            extraTypes[20] = typeof(ScramblePrgSt_v1);
            extraTypes[21] = typeof(ScramblePrgSt_v2);
            extraTypes[22] = typeof(ScramblePrgSt_v3);
            extraTypes[23] = typeof(Ts_loop2_st);
            extraTypes[24] = typeof(User_DataStream_st);
            extraTypes[25] = typeof(User_prgInfo_st);
        
        }

        public static void Serialize<T>(T o, string filePath)
        {
            SetTpyes();

            try
            {
                XmlSerializer formatter = new XmlSerializer(typeof(T), extraTypes);
               // XmlSerializer formatter = new XmlSerializer(o.GetType());
                StreamWriter sw = new StreamWriter(filePath, false);
                formatter.Serialize(sw, o);
                sw.Flush();
                sw.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public static T DeSerialize<T>(string filePath)
        {
            SetTpyes();
            try
            {
                XmlSerializer formatter = new XmlSerializer(typeof(T), extraTypes);
                StreamReader sr = new StreamReader(filePath);
                T o = (T)formatter.Deserialize(sr);
                sr.Close();
                return o;
            }
            catch (Exception)
            {

            }
            return default(T);
        }
    }
}


xml序列号比bin序列号失败概率大得多,所以,如何调试也是一个难题;

那就用到了之前的[System.Xml.Serialization.XmlIgnoreAttribute],它就是[XmlIgnore],用[XmlIgnore]需引用using System.Xml.Serialization;

xml序列号不成功,只看见一系列报错,而我们又不知道是哪个属性造成的,那就只有在类属性中一行一行注释测试,一般来说数组类,ArrayList等更容易出错

例如:

    [Serializable]
    public struct Tuner6ASI2in2C_ConfigSt
    {
        public int devCode;

        public MuxDbSaveSt muxDb;

       //[System.Xml.Serialization.XmlIgnoreAttribute]
        public object[] tuner; // TunerConfigSt_dvbS

        //[System.Xml.Serialization.XmlIgnoreAttribute]
        public UcCaDbSt[] caDb;
       //[System.Xml.Serialization.XmlIgnoreAttribute]
        public List<AcItemSt_v3> acList;

       [System.Xml.Serialization.XmlIgnoreAttribute]
        public List<ScramblePrgSt_v3>[] scr_Prog_arr;


       // [XmlIgnore]
        public int caCycle; // 加扰周期

        // 2
        public UcIpOut.UcIPOutDbSt ucIpOutDb;
        public UcIpSrcDbSt ucIpOutSrc;
        public UcIpDestDbSt4[] ucIpOutDest;

    }

 这么多数组,是在public List<ScramblePrgSt_v3>[] scr_Prog_arr;这里出错的,注释掉后就能生成xml文件的了。想办法弄成ArrayList才可以!否则就只能忽略该属性的了。


总结,不能xml序列化和反序列化的类型:

1.ArrayList数组:ArrayList[]

2.List数组:List[]

3.object数组:object[]

4.&#x0;代表byte中的0;

一般,数组才容易引起xml序列化不成功,但bin序列化没这些问题;而且,不是数组类型就不能xml序列化,例如:结构体数组,int[],bool[]等xml序列化没问题的,但object[]用xml序列化没成功。


15:59 2017/3/6



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值