对于我这样一个半路的业余爱好者,我想,我只需要方便和实现我需要的功能,但微软咋就做的不那么方便的呢?我想序列化就是能实现一个对象,一个控件的参数可以直接存成文件(即序列化),用反序列化即可反向构建这个对象和控件参数,属性值等。
比如,我就需要界面上的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反序列化不成功的哈!反正是不支持,这个花了我好多天才发现问题所在的地方的,好累眼睛!�代表byte中的0;
<prgName>www�����������������</prgName>
产生原因:string和byte[]之间转换造成,
之前使用的userPrgInfo.prgName = Encoding.GetEncoding("gbk").GetString(prg.ts.programName);
变为userPrgInfo.prgName = Encoding.GetEncoding("gbk").GetString(prg.ts.programName).TrimEnd('\0');即可解决。
网上有朋友有别的方法,如下:
如果反序列化时未给这种做特殊处理,反序列化将失败,如果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.�代表byte中的0;
一般,数组才容易引起xml序列化不成功,但bin序列化没这些问题;而且,不是数组类型就不能xml序列化,例如:结构体数组,int[],bool[]等xml序列化没问题的,但object[]用xml序列化没成功。
15:59 2017/3/6

本文详细介绍了C#中序列化与反序列化的基本概念,包括Bin序列化与XML序列化的区别,针对TreeView控件的序列化实现,并提供了使用方法和注意事项。还分享了自定义XML序列化类的扩展方法,允许序列化多种类型,并解决了序列化过程中可能出现的问题。

被折叠的 条评论
为什么被折叠?



