- 原先一直用BinaryFormatter来序列化挺好,可是最近发现在WinCE下是没有办法进行BinaryFormatter操作,很不爽,只能改成了BinaryWriter和BinaryReader来读写,突然想到能不能用XML来序列化?于是在网上查了些资料便写了些实践性代码,做些记录,避免以后忘记。
- 序列化对象
- public class People
- {
- [XmlAttribute("NAME")]
- public string Name
- { set; get; }
- [XmlAttribute("AGE")]
- public int Age
- { set; get; }
- }
- [XmlRoot("Root")]
- public class Student : People
- {
- [XmlElement("CLASS")]
- public string Class
- { set; get; }
- [XmlElement("NUMBER")]
- public int Number
- { set; get; }
- }
- void Main(string[] args)
- {
- Student stu = new Student()
- {
- Age = 10,
- Class = "Class One",
- Name = "Tom",
- Number = 1
- };
- XmlSerializer ser = new XmlSerializer(typeof(Student));
- ser.Serialize(File.Create("C:\\x.xml"), stu);
- }
- 反序列化对象
- XmlSerializer ser = new XmlSerializer(typeof(Student));
- Student stu = ser.Deserialize(File.OpenRead("C:\\x.xml")) as Student;
- 对象数组序列化
- public class People
- {
- [XmlAttribute("NAME")]
- public string Name
- { set; get; }
- [XmlAttribute("AGE")]
- public int Age
- { set; get; }
- }
- [XmlRoot("Root")]
- public class Student : People
- {
- [XmlElement("CLASS")]
- public string Class
- { set; get; }
- [XmlElement("NUMBER")]
- public int Number
- { set; get; }
- }
- void Main(string[] args)
- {
- List<Student> stuList = new List<Student>();
- stuList.Add(new Student() { Age = 10, Number = 1, Name = "Tom", Class = "Class One" });
- stuList.Add(new Student() { Age = 11, Number = 2, Name = "Jay", Class = "Class Two" });
- stuList.Add(new Student() { Age = 12, Number = 3, Name = "Pet", Class = "Class One" });
- stuList.Add(new Student() { Age = 13, Number = 4, Name = "May", Class = "Class Three" });
- stuList.Add(new Student() { Age = 14, Number = 5, Name = "Soy", Class = "Class Two" });
- XmlSerializer ser = new XmlSerializer(typeof(List<Student>));
- ser.Serialize(File.Create("C:\\x.xml"), stuList);
- }
- 对象数组反序列
- XmlSerializer ser = new XmlSerializer(typeof(List<Student>));
- List<Student> stuList = ser.Deserialize(File.OpenRead("C:\\x.xml")) as List<Student>;
- foreach (Student s in stuList)
- {
- MessageBox.Show(string.Format("{0} : {1} : {2} : {3}",
- s.Name, s.Age, s.Class, s.Number));
- }
- 序列化Dirctionary
- public struct DirectionList
- {
- [XmlAttribute("Name")]
- public string Name;
- [XmlElement("Value")]
- public int Value;
- }
- void Main(string[] args)
- {
- Dictionary<string, int> list = new Dictionary<string, int>();
- list.Add("1", 100);
- list.Add("2", 200);
- list.Add("3", 300);
- list.Add("4", 400);
- list.Add("5", 500);
- list.Add("6", 600);
- list.Add("7", 700);
- list.Add("8", 800);
- list.Add("9", 900);
- List<DirectionList> dirList = new List<DirectionList>();
- foreach (var s in list)
- {
- dirList.Add(new DirectionList() { Name = s.Key, Value = s.Value });
- }
- XmlSerializer ser = new XmlSerializer(typeof(List<DirectionList>));
- ser.Serialize(File.Create("C:\\x.xml"), dirList);
- }
- 这里还要讲一点,在XmlSerializer中,不支持Dirctionary<>类型的对象,所以在序列化这种最常见类型的时候,只能按照它的格式先创建一个可以别序列化的类型,这里我定义了一个结构体,当然你也可以定义成其他的类。将Dictionary<>中的数据依次放进结构体以后就可以放入流中了。
- [XmlAttribute("Name")]意思是将这个字段作为xml的属性,属性名跟在“”中
- [XmlElement("Value")]意思是将这个字段做为xml的元素。
- 反序列化Dirctionary
- XmlSerializer ser = new XmlSerializer(typeof(List<DirectionList>));
- List<DirectionList> dirList = ser.Deserialize(
- File.OpenRead("C:\\x.xml")) as List<DirectionList>;
- foreach (var v in dirList)
- {
- Console.WriteLine("{0} : {1}", v.Name, v.Value);
- }
- 其实我并不喜欢这个名称,感觉有点生化危机的feel,但是也就是这样了,没有太炫的地方,Deserialize反序列化。真希望.Net能集成Dirctionary<>对象,那我们这些懒人就方便了。
- 在需要序列化的队伍中,数组是很常见的类型,其次就是图片了
- 序列化图片
- public struct ImageStruct
- {
- [XmlAttribute("Number")]
- public int number;
- [XmlElement("Image")]
- public byte[] picture;
- }
- void Main(string[] args)
- {
- ImageStruct s = new ImageStruct() { number = 1, picture = File.ReadAllBytes(@"11.jpg") };
- XmlSerializer ser = new XmlSerializer(typeof(ImageStruct));
- FileStream fs = File.Create("c:\\x.xml");
- ser.Serialize(fs, s);
- fs.Close();
- }
- 一样的,采用结构体来保存图片,这里我还加了个图片的名字,到时候查找起来也方便一些
- 图片反序列化
- XmlSerializer ser = new XmlSerializer(typeof(ImageStruct));
- ImageStruct s = (ImageStruct)ser.Deserialize(File.OpenRead("c:\\x.xml"));
- pictureBox1.Image = Image.FromStream(new MemoryStream(s.picture));
- 没有花头的方式,利用memorystream来做缓存,这样会比较快一点,实际上我并没有怎么感觉。
- 图片数组序列化
- public struct ImageStruct
- {
- [XmlAttribute("Number")]
- public int number;
- [XmlElement("Image")]
- public byte[] picture;
- }
- void Main(string[] args)
- {
- List<ImageStruct> imageList = new List<ImageStruct>();
- imageList.Add(new ImageStruct()
- {
- number = 1,
- picture = File.ReadAllBytes(@"11.jpg")
- });
- imageList.Add(new ImageStruct()
- {
- number = 2,
- picture = File.ReadAllBytes(@"22.jpg")
- });
- XmlSerializer ser = new XmlSerializer(typeof(List<ImageStruct>));
- FileStream fs = File.Create("c:\\x.xml");
- ser.Serialize(fs, imageList);
- fs.Close();
- }
- 图片数组反序列化
- XmlSerializer ser = new XmlSerializer(typeof(List<ImageStruct>));
- List<ImageStruct> s = (List<ImageStruct>)ser.Deserialize(File.OpenRead("c:\\x.xml"));
- var im = from i in s
- where i.number == 1
- select i.picture;
- //var im = s.Where(p => p.number == 1).Select(p => p.picture);
- foreach (var image in im)
- {
- pictureBox1.Image = Image.FromStream(
- new MemoryStream(image));
- }
- 这里还对数组结构进行了Linq查询,这样就可以很方便的查询图片了。
- XML序列化与反序列化 整理文档XML序列化与反序列化 整理文档
- XML序列化与反序列化
- // OBJECT -> XML
- public static void SaveXml(string filePath, object obj) { SaveXml(filePath, obj, obj.GetType()); }
- public static void SaveXml(string filePath, object obj, System.Type type)
- {
- using (System.IO.StreamWriter writer = new System.IO.StreamWriter(filePath))
- {
- System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(type);
- xs.Serialize(writer, obj);
- writer.Close();
- }
- }
- // XML -> OBJECT
- public static object LoadXml(string filePath, System.Type type)
- {
- if (!System.IO.File.Exists(filePath))
- return null;
- using (System.IO.StreamReader reader = new System.IO.StreamReader(filePath))
- {
- System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(type);
- object obj = xs.Deserialize(reader);
- reader.Close();
- return obj;
- }
- }
- 相关的常用Attribute(命名空间System.Xml.Serialization )
- [XmlRootAttribute("PurchaseOrder", Namespace="http://www.cpandl.com", IsNullable=false)] // 指定根
- [XmlIgnoreAttribute] // 跳过不序列化
- [XmlArrayAttribute("Items")] public OrderedItem[] OrderedItems; // 层次序列化: <Items><OrderedItem.../><OrderedItem.../>..</Items>
- [XmlElementAttribute(ElementName="Link", IsNullable=false)] public Link[] Links; // 平面序列化: <Link ..../><Link .../>...
- [XmlAttribute("Cat")] public string Cat; // 表现为属性<... Cat=.. />
- [XmlElementAttribute(IsNullable=false)] // 表现为节点<Cat>..</cat>
- 相关的全部Attribute(命名空间System.Xml.Serialization )
- XmlAttributes 表示一个特性对象的集合,这些对象控制 XmlSerializer 如何序列化和反序列化对象。
- XmlArrayAttribute 指定 XmlSerializer 应将特定的类成员序列化为 XML 元素数组。
- XmlArrayItemAttribute 指定 XmlSerializer 可以放置在序列化数组中的派生类型。
- XmlArrayItemAttributes 表示 XmlArrayItemAttribute 对象的集合。
- XmlAttributeAttribute 指定 XmlSerializer 应将类成员作为 XML 特性序列化。
- XmlChoiceIdentifierAttribute 指定可以通过使用枚举来进一步消除成员的歧义。
- XmlElementAttribute 在 XmlSerializer 序列化或反序列化包含对象时,指示公共字段或属性表示 XML 元素。
- XmlElementAttributes 表示 XmlElementAttribute 的集合,XmlSerializer 将其用于它重写序列化类的默认方式。
- XmlEnumAttribute 控制 XmlSerializer 如何序列化枚举成员。
- XmlIgnoreAttribute 指示 XmlSerializer 的 Serialize 方法不序列化公共字段或公共读/写属性值。
- XmlIncludeAttribute 允许 XmlSerializer 在它序列化或反序列化对象时识别类型。
- XmlRootAttribute 控制视为 XML 根元素的属性目标的 XML 序列化。
- XmlTextAttribute 当序列化或反序列化包含类时,向 XmlSerializer 指示应将此成员作为 XML 文本处理。
- XmlTypeAttribute 控制当属性目标由 XmlSerializer 序列化时生成的 XML 架构。
- XmlAnyAttributeAttribute 指定成员(返回 XmlAttribute 对象的数组的字段)可以包含任何 XML 属性。
- XmlAnyElementAttribute 指定成员(返回 XmlElement 或 XmlNode 对象的数组的字段)可以包含对象,该对象表示在序列化或反序列化的对象中没有相应成员的所有 XML 元素。
- XmlAnyElementAttributes 表示 XmlAnyElementAttribute 对象的集合。
- XmlAttributeEventArgs 为 UnknownAttribute 事件提供数据。
- XmlAttributeOverrides 允许您在使用 XmlSerializer 序列化或反序列化对象时重写属性、字段和类特性。
- XmlElementEventArgs 为 UnknownElement 事件提供数据。
- XmlNamespaceDeclarationsAttribute 指定目标属性、参数、返回值或类成员包含与 XML 文档中所用命名空间关联的前缀。
- XmlNodeEventArgs 为 UnknownNode 事件提供数据。
- XmlSerializer 将对象序列化到 XML 文档中和从 XML 文档中反序列化对象。XmlSerializer 使您得以控制如何将对象编码到 XML 中。
- XmlSerializerNamespaces 包含 XmlSerializer 用于在 XML 文档实例中生成限定名的 XML 命名空间和前缀。
- XmlTypeMapping 包含从一种类型到另一种类型的映射。
- xml序列化答疑
- (1)需序列化的字段必须是公共的(public)
- (2)需要序列化的类都必须有一个无参的构造函数
- (3)枚举变量可序列化为字符串,无需用[XmlInclude]
- (4)导出非基本类型对象,都必须用[XmlInclude]事先声明。该规则递归作用到子元素
- 如导出ArrayList对象,若其成员是自定义的,需预包含处理:
- using System.Xml.Serialization;
- [XmlInclude(typeof(自定义类))]
- (5)Attribute中的IsNullable参数若等于false,表示若元素为null则不显示该元素。
- 也就是说:针对值类型(如结构体)该功能是实效的
- 若数组包含了100个空间,填充了10个类对象,则序列化后只显示10个节点
- 若数组包含了100个空间,填充了10个结构体对象,则序列化后会显示100个节点
- (6)真正无法XML序列化的情况
- 某些类就是无法XML序列化的(即使使用了[XmlInclude])
- IDictionary(如HashTable)
- System.Drawing.Color
- System.Drawing.Font
- SecurityAttribute声明
- 父类对象赋予子类对象值的情况
- 对象间循环引用
- (7)对于无法XML序列化的对象,可考虑
- 使用自定义xml序列化(实现IXmlSerializable接口)
- 实现IDictionary的类,可考虑(1)用其它集合类替代;(2)用类封装之,并提供Add和this函数
- 某些类型需要先经过转换,然后才能序列化为 XML。如XML序列化System.Drawing.Color,可先用ToArgb()将其转换为整数
- 过于复杂的对象用xml序列化不便的话,可考虑用二进制序列化
- ------------------------------------------------------------------------------------
- 高级议题
- ------------------------------------------------------------------------------------
- 序列化中异常的扑捉
- 使用Exception.Message只会得到简单的信息“行***错误"
- 可以使用Exception.InnerException.Message得到更详尽的信息
- 可使用事件代理来处理解析不了的XML节点
- XmlSerializer serializer = new XmlSerializer(typeof(PurchaseOrder));
- serializer.UnknownNode+= new XmlNodeEventHandler(serializer_UnknownNode);
- serializer.UnknownAttribute+= new XmlAttributeEventHandler(serializer_UnknownAttribute);
- protected void serializer_UnknownNode(object sender, XmlNodeEventArgs e)
- {
- Console.WriteLine("Unknown Node:" + e.Name + "\t" + e.Text);
- }
- protected void serializer_UnknownAttribute(object sender, XmlAttributeEventArgs e)
- {
- System.Xml.XmlAttribute attr = e.Attr;
- Console.WriteLine("Unknown attribute " + attr.Name + "='" + attr.Value + "'");
- }
- 集合类(IEnumerable, ICollection)必须满足下列规则才可XML序列化:
- - 不得实现 IDictionary。
- - 必须有一个 Add 方法,该方法不是由该接口定义的,因为它通常是为该集合将要容纳的专用类型而创建的
- - 必须有一个索引器, 且参数为 System.Int32 (C# int)
- - 在 Add、Count 和索引器中不能有任何安全特性(SecurityAttribute)
- 可序列化集合类例程:
- public class PublisherCollection : CollectionBase
- {
- public int Add(Publisher value)
- {
- return base.InnerList.Add(value);
- }
- public Publisher this[int idx]
- {
- get { return (Publisher) base.InnerList[idx]; }
- set { base.InnerList[idx] = value; }
- }
- }
- 某些类是以程序集的形式提供的,无法修改其源码。可用XmlAttributeOverrides设置其序列化特性
- XML目标
- <?xml version="1.0" encoding="utf-8"?>
- <Inventory xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <Product>
- <ProductID>100</ProductID>
- <ProductName>Product Thing</ProductName>
- <SupplierID>10</SupplierID>
- </Product>
- <Book>
- <ProductID>101</ProductID>
- <ProductName>How to Use Your New Product Thing</ProductName>
- <SupplierID>10</SupplierID>
- <ISBN>123456789</ISBN>
- </Book>
- </Inventory>
- 源类(无法修改)
- public class Inventory
- {
- private Product[] stuff;
- public Inventory() {}
- public Product[] InventoryItems {get {return stuff;} set {stuff=value;}}
- }
- 附加XmlAttributeOverrides后即可序列化
- XmlAttributes attrs = new XmlAttributes();
- attrs.XmlElements.Add(new XmlElementAttribute("Book", typeof(BookProduct)));
- attrs.XmlElements.Add(new XmlElementAttribute("Product", typeof(Product)));
- //add to the Attributes collection
- XmlAttributeOverrides attrOver = new XmlAttributeOverrides();
- attrOver.Add(typeof(Inventory), "InventoryItems", attrs);
- //deserialize and load data into the listbox from deserialized object
- FileStream f=new FileStream("..\\..\\..\\inventory.xml",FileMode.Open);
- XmlSerializer newSr=new XmlSerializer(typeof(Inventory), attrOver);
- Inventory newInv = (Inventory)newSr.Deserialize(f);
- ------------------------------------------------------------------------------------
- 最简单的示例
- -------------------------------------------------------------------------------------
- 类设计
- public class MyClass {public MyObject MyObjectProperty;}
- public class MyObject {public string ObjectName;}
- 序列化的 XML:
- <MyClass>
- <MyObjectProperty>
- <Objectname>My String</ObjectName>
- </MyObjectProperty>
- </MyClass>
- ------------------------------------------------------------------------------------
- 示例: 序列化数组,并限制数组元素类型
- -------------------------------------------------------------------------------------
- 类设计
- public class Things
- {
- [XmlElement(DataType = typeof(string)), XmlElement(DataType = typeof(int))]
- public object[] StringsAndInts;
- }
- 生成的 XML 可能为:
- <Things>
- <string>Hello</string>
- <int>999</int>
- <string>World</string>
- </Things>
- -------------------------------------------------------------------------------------
- 示例: 序列化数组
- -------------------------------------------------------------------------------------
- 类设计
- using System.Xml.Serialization;
- [XmlRootAttribute("LinkLibrary", IsNullable = false, Namespace="http://www.wztelecom.cn")]
- public class LinkLib
- {
- [XmlElementAttribute(ElementName="Link", IsNullable=false)]
- public Link[] Links;
- public LinkLib()
- {
- Links = new Link[50];
- Links[0] = new Link("aa", "aa", "aa");
- Links[1] = new Link("bb", "aa", "aa");
- Links[2] = new Link("cc", "aa", "aa");
- Links[3] = new Link("aa", "aa", "aa");
- Links[4] = new Link("aa", "aa", "aa");
- Links[5] = new Link("aa", "aa", "aa");
- Links[6] = new Link("aa", "aa", "aa");
- Links[7] = new Link("aa", "aa", "aa");
- Links[8] = new Link("aa", "aa", "aa");
- Links[9] = new Link("aa", "aa", "aa");
- }
- }
- public class Link
- {
- [XmlAttribute("Cat")] public string Cat;
- [XmlAttribute("Url")] public string Url;
- [XmlAttribute("Desc")]public string Desc;
- public Link(){}
- public Link(string cat, string url, string desc)
- {
- Cat = cat;
- Url = url;
- Desc = desc;
- }
- }
- 目标XML文件
- <?xml version="1.0" encoding="utf-8"?>
- <LinkLibrary xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="bb" Url="aa" Desc="aa" />
- <Link Cat="cc" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- </LinkLibrary>
- 若使用[XmlArrayAttribute("Links")] public Link[] Links;则序列化后的xml文件会多出一层:
- <?xml version="1.0" encoding="utf-8"?>
- <LinkLibrary xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <Links>
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="bb" Url="aa" Desc="aa" />
- <Link Cat="cc" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- <Link Cat="aa" Url="aa" Desc="aa" />
- </Links>
- </LinkLibrary>
- -------------------------------------------------------------------------------------
- 示例:使用自定义序列化序列化Dictionary对象
- -------------------------------------------------------------------------------------
- XML目标
- <?xml version="1.0" encoding="utf-8"?>
- <FactTableDef>
- <Name>FactTableDef1</Name>
- <Owner>owner1</Owner>
- <SourceTable>sourceTable1</SourceTable>
- <ColumnMeasureMaps>
- <Map Column="column1" Measure="Measure1" />
- <Map Column="column2" Measure="Measure2" />
- <Map Column="column3" Measure="Measure3" />
- </ColumnMeasureMaps>
- <ColumnDimensionMaps>
- <Map Column="column4" Dimension="Dimension4" />
- <Map Column="column5" Dimension="Dimension5" />
- <Map Column="column6" Dimension="Dimension6" />
- </ColumnDimensionMaps>
- </FactTableDef>
- 类源码
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Runtime.Serialization;
- using System.Xml;
- using System.Xml.Serialization;
- namespace WZDM.OLAP
- {
- [System.Serializable()]
- [XmlInclude(typeof(FactTableDef))]
- public class FactTableDef : System.Xml.Serialization.IXmlSerializable
- {
- public string Name; // 名称
- public string Owner; // 事实表属主
- public string SourceTable; // 源表
- public Dictionary<string, string> ColumnMeasureMaps; // 字段和量度对应关系
- public Dictionary<string, string> ColumnDimensionMaps; // 字段和维度对应关系
- public FactTableDef() { }
- ...
- public void WriteXml(System.Xml.XmlWriter writer)
- {
- writer.WriteElementString("Name", this.Name);
- writer.WriteElementString("Owner", this.Owner);
- writer.WriteElementString("SourceTable", this.SourceTable);
- // ColumnMeasureMaps
- writer.WriteStartElement("ColumnMeasureMaps");
- foreach (string key in this.ColumnMeasureMaps.Keys)
- {
- writer.WriteStartElement("Map");
- writer.WriteAttributeString("Column", key);
- writer.WriteAttributeString("Measure", ColumnMeasureMaps[key]);
- writer.WriteEndElement();
- }
- writer.WriteEndElement();
- // ColumnDimensionMaps
- writer.WriteStartElement("ColumnDimensionMaps");
- foreach (string key in this.ColumnDimensionMaps.Keys)
- {
- writer.WriteStartElement("Map");
- writer.WriteAttributeString("Column", key);
- writer.WriteAttributeString("Dimension", ColumnDimensionMaps[key]);
- writer.WriteEndElement();
- }
- writer.WriteEndElement();
- }
- public void ReadXml(System.Xml.XmlReader reader)
- {
- reader.Read();
- this.Name = reader.ReadElementString("Name");
- this.Owner = reader.ReadElementString("Owner");
- this.SourceTable = reader.ReadElementString("SourceTable");
- // ColumnMeasureMaps
- ColumnMeasureMaps = new Dictionary<string, string>();
- reader.ReadStartElement("ColumnMeasureMaps");
- reader.ReadToDescendant("Map");
- do
- {
- string key = reader.GetAttribute("Column");
- string item = reader.GetAttribute("Measure");
- ColumnMeasureMaps.Add(key, item);
- }while (reader.ReadToNextSibling("Map"));
- reader.ReadEndElement();
- // ColumnDimensionMaps
- ColumnDimensionMaps = new Dictionary<string, string>();
- reader.ReadStartElement("ColumnDimensionMaps");
- reader.ReadToDescendant("Map");
- do
- {
- string key = reader.GetAttribute("Column");
- string item = reader.GetAttribute("Dimension");
- ColumnDimensionMaps.Add(key, item);
- } while (reader.ReadToNextSibling("Map"));
- reader.ReadEndElement();
- }
- }
- }