实现动态的XML文件读写操作
实现动态的XML文件读写操作(依然带干货)
前言
最近由于项目需求,需要读写操作XML文件,并且存储的XML文件格式会随着导入的数据不同而随时改变(当然导入的数据还是有一定约束的),这样我们要预先定义好XML文件的格式就不太现实了,如何实现不管导入的数据如何变化,我都能正确的把数据解析出来,这就是要实现的动态的XML文件读写操作!如果大家有更好的方式欢迎交流!
具体实现
本文所实现的读写XML文件是使用序列话的方式,具体博文请参考:http://www.cnblogs.com/fish-li/archive/2013/05/05/3061816.html,当然如果只是序列化操作XML文件的话,只需要看这篇博文,也就不需要这篇文章了!
了解了如何序列化操作XML文件了话,你就会知道,要想写入和读取XML文件,我们就需要定义好一个数据类型(这一点很重要),但是问题就出现了,如果我们在编程时就定义好一个数据类型了,当导入的数据改变了,这个数据类型就不适合了,接下来就来解决这个问题
实现一:根据需求创建动态数据类型
废话先不多说,先上代码,代码说话,往往比语言来的直接也更容易懂

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Diagnostics; namespace XMLDemo
{
public class ReflectClass
{
//保存动态生成并编译的类的type对象
Type theType = null;
//保存动态生成类的实例
object theClass = null;
public Assembly DoOperation()
{
//未初始化
if (theType == null)
{
//初始化
return GenerateCode();
}
return null;
}
private Assembly GenerateCode()
{
//文件名
string fileName = "XmlClass";
////从编译好的dll文件load一个Assembly
//Assembly a = Assembly.LoadFrom(fileName + ".dll"); //从编译好的dll文件load一个Assembly
byte[] filedata = File.ReadAllBytes(fileName + ".dll");
Assembly a = Assembly.Load(filedata); //此方法在使用完dll文件后会自动释放资源
return a;
}
public Assembly DoOperation(List<ExcelData> list)
{
//未初始化
if (theType == null)
{
//初始化
return GenerateCode(list);
}
return null;
}
private Assembly GenerateCode(List<ExcelData> list)
{
//文件名
string fileName = "XmlClass";
//打开文件,如果不存在,则创建
Stream s = File.Open(fileName + ".cs", FileMode.Create);
//创建一个StreamWriter来写入数据
StreamWriter wrtr = new StreamWriter(s); #region 写入动态创建类的源代码
wrtr.WriteLine("// 动态创建的XmlClass类文件"); //类名,此类是为序列化读取XML文件创建的类文件
string className = "XmlClass";
wrtr.WriteLine("using System;");
wrtr.WriteLine("using System.Xml.Serialization;");
wrtr.WriteLine("public class {0}", className);
wrtr.WriteLine("{");
var ch = (from num in list select num.Mark).Distinct().ToList();
foreach (var n in ch)
{
wrtr.WriteLine("\tpublic " + n + " " + n);
wrtr.WriteLine("\t{");
wrtr.WriteLine("\t\tget;set;");
wrtr.WriteLine("\t}");
}
wrtr.WriteLine("}");
foreach (var n in ch)
{
wrtr.WriteLine("public class {0}", n);
wrtr.WriteLine("{");
var nlist = from num in list where (num.Mark == n) select num;
foreach (var m in nlist)
{
wrtr.WriteLine("\tpublic string " + m.Name);
wrtr.WriteLine("\t{");
wrtr.WriteLine("\t\tget;set;");
wrtr.WriteLine("\t}");
}
wrtr.WriteLine("}");
}
//关闭StreamWriter和文件
wrtr.Close();
s.Close();
#endregion //启动进程编译源文件
//指定参数
ProcessStartInfo psi = new ProcessStartInfo();
File.Delete(fileName + ".dll"); //重新导入数据时删除旧的DLL文件
//启动cmd.exe
psi.FileName = "cmd.exe";
//cmd.exe的参数,/c-close,完成后关闭;后为参数,指定cmd.exe使用csc来编译刚才生成的源文件
string compileString = "/c C:\\WINDOWS\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe /optimize+ /target:library {0}.cs";
psi.Arguments = String.Format(compileString, fileName);
//运行时的风格-最小化
psi.WindowStyle = ProcessWindowStyle.Minimized;
//启动进程
Process proc = Process.Start(psi);
//指定当前在此进程退出前等待
proc.WaitForExit();
//从编译好的dll文件load一个Assembly
byte[] filedata = File.ReadAllBytes(fileName + ".dll");
Assembly a = Assembly.Load(filedata); //此方法在使用完dll文件后会自动释放资源
//Assembly a = Assembly.LoadFrom(fileName + ".dll"); //这样使用dll文件会一直被占用,不会释放,造成重新生成前无法自动删除
//删除源文件
//File.Delete(fileName + ".cs");
return a;
}
}
}

以上 ReflectClass类帮助我们实现了通过导入的数据来创建一个供我们使用的编译好的类文件,下面主要讲如果通过这个使用这个编译好的dll文件来写入我们的XML文件
写入动态创建类的源代码那一块真是费了我不少脑细胞,感觉跟写模板类似的!(大家如果根据自己需求改写的话,应该就会体会到)
实现二:通过反射得到动态创建的数据类型并序列化写入XML文件
还是先上代码,XMLHelper帮助类可以去上面的连接去下载,也可以在我提供的Demo里下载,我只根据我的需要添加了一个方法,下面我的一个普通帮助类CommonHelper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO; namespace XMLDemo
{
public class CommonHelper
{
/// <summary>
/// 写文件
/// </summary>
/// <param name="filePath">文件名</param>
/// <param name="Context">写的内容</param>
/// <returns>是否成功</returns>
public static bool FileWriter(string filePath, string Context)
{
try
{
//打开文件,如果不存在,则创建
Stream s = File.Open(filePath, FileMode.Create);
//创建一个StreamWriter来写入数据
StreamWriter wrtr = new StreamWriter(s);
//写入动态创建类的源代码
wrtr.WriteLine(Context);
wrtr.Close();
s.Close();
return true;
}
catch (Exception)
{ return false;
}
}
/// <summary>
/// 读文件
/// </summary>
/// <param name="filePath">文件名</param>
/// <returns>返回读的内容</returns>
public static string FileRead(string filePath)
{
try
{
//打开文件,如果不存在,则创建
Stream s1 = File.Open(filePath, FileMode.Open);
//创建一个StreamWriter来写入数据
StreamReader reader = new StreamReader(s1);
//写入动态创建类的源代码
string xml = reader.ReadToEnd();
reader.Close();
s1.Close();
return xml;
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// 根据数据创建类,并得到动态创建类的集合
/// </summary>
/// <param name="list">导入的数据集合</param>
/// <returns>返回类的集合</returns>
public static List<object> GetXmlClassInstances(List<ExcelData> list)
{
List<object> o = new List<object>();
ReflectClass t = new ReflectClass();
var assemblys = t.DoOperation(list);
Type[] types = assemblys.GetExportedTypes();
foreach (Type type in types)
{
o.Add(assemblys.CreateInstance(type.Name));
}
return o;
}
/// <summary>
/// 得到动态创建类的集合
/// </summary>
/// <returns></returns>
public static List<object> GetXmlClassInstances()
{
List<object> o = new List<object>();
ReflectClass t = new ReflectClass();
var assemblys = t.DoOperation();
Type[] types = assemblys.GetExportedTypes();
foreach (Type type in types)
{
o.Add(assemblys.CreateInstance(type.Name));
}
return o;
}
}
}

主要是一个GetXmlClassInstances(List<ExcelData> list):根据数据创建类,并得到动态创建类的集合
一个是GetXmlClassInstances():得到已经创建好的动态类的集合
下面是一个数据实体类,也就是我们所规范的数据格式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace XMLDemo
{
/// <summary>
/// 数据实体类
/// </summary>
public class ExcelData
{
/// <summary>
/// 根节点
/// </summary>
public string Mark { get; set; }
/// <summary>
/// 子节点
/// </summary>
public string Name { get; set; } /// <summary>
/// 子节点对应值
/// </summary>
public string Value { get; set; }
}
}

准备工作就绪后就可以进行XML文件的写入了,依然是废话不多说,上代码:

private void btnWrite_Click(object sender, EventArgs e)
{
List<object> XmlClassInstances = CommonHelper.GetXmlClassInstances(listData);
if (InsertXmlClass(XmlClassInstances, listData) == false)
{
MessageBox.Show("数据导入失败");
return;
}
}
private bool InsertXmlClass(List<object> o, List<ExcelData> list)
{ for (int i = 1; i < o.Count; i++)
{
//给类的属性赋值
var nlist = from num in list where (num.Mark == o[i].GetType().Name) select num;
foreach (var model in nlist)
{
PropertyInfo propinfo = o[i].GetType().GetProperty(model.Name);
propinfo.SetValue(o[i], model.Value, null);
}
}
var XmlClass = o[0]; //默认第一个类为主体类,主体类的属性为其他类
var tt = XmlClass.GetType();
for (int i = 1; i < o.Count; i++)
{
//给主体类的属性赋值
PropertyInfo propinfo = tt.GetProperty(o[i].GetType().Name);
propinfo.SetValue(XmlClass, o[i], null);
}
//序列化主体类,得到序列化字符串
string xml = XmlHelper.XmlSerialize(XmlClass, Encoding.UTF8);
string FilePath = "QMSPlan.XML";
if (CommonHelper.FileWriter(FilePath, xml) == false)
{
return false;
}
return true;
}

上面的代码可能有点绕,大家可以单步调试去理解,当时写的时候崩溃了几次,最后才调试好,不知道有什么更好的写法!
实现三:序列化读出XML文件
感觉用语言都表达不出来,还是直接上代码吧

private void btnRead_Click(object sender, EventArgs e)
{
List<ExcelData> listRead = new List<ExcelData>();
var XmlClass = GetXmlClass();
if (XmlClass == null)
{
MessageBox.Show("数据读取失败");
return;
}
//获取所有主体类的属性(即所有的子类集合)
PropertyInfo[] ps = XmlClass.GetType().GetProperties();
foreach (var n in ps)
{
//得到子类
var m = n.GetValue(XmlClass, null);
//获取子类的所有属性
PropertyInfo[] x = m.GetType().GetProperties();
foreach (var y in x)
{
ExcelData model = new ExcelData();
model.Mark = m.GetType().Name;
model.Name = y.Name;
model.Value = y.GetValue(m, null).ToString();
listRead.Add(model);
}
}
}
private object GetXmlClass()
{
List<object> o = CommonHelper.GetXmlClassInstances();
var XmlClass = o[0]; //默认第一个类为主体类 string FilePath = "QMSPlan.XML";
string xml = CommonHelper.FileRead(FilePath);
if (xml == null)
{
return null;
}
XmlClass = XmlHelper.XmlDeserialize(XmlClass.GetType(), xml, Encoding.UTF8);
return XmlClass;
}

上面大量运用了反射的特性,就是因为实现动态读取数据类型而造成的!
结束语
可能大家看完觉得完全没必要这样做,并且大量这样的操作会影响性能,不过这样做实实在在解决了我项目中的难点,实现了根据导入数据的不同,可以实现正确的XML的读写操作,
总结一下:以上总共有三个知识点的应用
1.动态创建数据类型并在程序中使用
2.序列话读写XML文件
3.利用反射特性实现
最后附上demo下载地址:http://files.cnblogs.com/beimeng/XML.demo.rar
实现动态的XML文件读写操作的更多相关文章
- 实现动态的XML文件读写操作(依然带干货)
前言 最近由于项目需求,需要读写操作XML文件,并且存储的XML文件格式会随着导入的数据不同而随时改变(当然导入的数据还是有一定约束的),这样我们要预先定义好XML文件的格式就不太现实了,如何实现不管 ...
- ios 简单的plist文件读写操作(Document和NSUserDefaults)
最近遇到ios上文件读写操作的有关知识,记录下来,以便以后查阅,同时分享与大家. 一,简单介绍一下常用的plist文件. 全名是:Property List,属性列表文件,它是一种用来存储串行化后的对 ...
- QXmlStreamReader/QXmlStreamWriter实现Qt下xml文件读写
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QXmlStreamReader/QXmlStreamWriter实现Qt下xml文件读写 ...
- c语言文件读写操作总结
C语言文件读写操作总结 C语言文件操作 一.标准文件的读写 1.文件的打开 fopen() 文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程 ...
- [转]Android - 文件读写操作 总结
转自:http://blog.csdn.net/ztp800201/article/details/7322110 Android - 文件读写操作 总结 分类: Android2012-03-05 ...
- PHP文件读写操作之文件写入代码
在PHP网站开发中,存储数据通常有两种方式,一种以文本文件方式存储,比如txt文件,一种是以数据库方式存储,比如Mysql,相对于数据库存储,文件存储并没有什么优势,但是文件读写操作在基本的PHP开发 ...
- 更新java对xml文件的操作
//更新java在xml文件中操作的内容 public static void upda(Document doc) throws Exception{ //创建一个TransformerFactor ...
- Java 字节流实现文件读写操作(InputStream-OutputStream)
Java 字节流实现文件读写操作(InputStream-OutputStream) 备注:字节流比字符流底层,但是效率底下. 字符流地址:http://pengyan5945.iteye.com/b ...
- Java 字符流实现文件读写操作(FileReader-FileWriter)
Java 字符流实现文件读写操作(FileReader-FileWriter) 备注:字符流效率高,但是没有字节流底层 字节流地址:http://pengyan5945.iteye.com/blog/ ...
随机推荐
- sql server 查看表的行数
SELECT a.name , b.[rows]FROM dbo.sysobjects AS a LEFT JOIN sysindexes AS b ON a.id ...
- 多线程学习之三生产者消费者模式Guarded Suspension
Guarded Suspension[生产消费者模式] 一:guarded suspension的参与者--->guardedObject(被防卫)参与者 1.1该 ...
- Yii2中如何使用CodeCeption
Yii2和CodeCeption CodeCeption是一个全栈的PHP测试框架,关于CodeCeption的介绍见:CodeCeption官方文档. Yii2官方增加了对CodeCeption的支 ...
- 探秘IntelliJ IDEA v13的应用服务器
原文:探秘IntelliJ IDEA v13的应用服务器 IntelliJ IDEA v13应用out-of-the-box支持众多企业级和开源的服务器,包括:GlassFish.WebLogic. ...
- linux有用技巧:使用快照制作虚拟机
在日常的学习其中,假设遇到了集群和负载均衡类的实验,须要用到大量的虚拟机,假设一个一个的去创建,显然是很费力和低效的.所以今天交给大家怎样用快照来制作虚拟机.想要多少给你多少^_^.仅仅要内存够用! ...
- 使用 C# 进行 Outlook 2007 编程
原文:使用 C# 进行 Outlook 2007 编程 探讨如何使用 C# 编程语言生成 Outlook 识别的应用程序和 Outlook 外接程序. 请从"Add References&q ...
- Linux下使用Photorec恢复误格U盘
photorec包含在testdisk软件包中, 所以直接通过包管理器直接安装testdisk安装即可. 使用root权限来运行软件,在终端键入 [shell] photorec [/shell] 然 ...
- VMWare 11安装操作系统 - 初学者系列 - 学习者系列文章
在2010年的时候,我写过一篇关于VMWare的安装操作系统的博文.但是今天在QQ群里有人问起VMWare安装操作系统的问题,虽然回答了,但是回头看了下当时那篇博文,决定重新写一文. 首先要获取VMW ...
- C#动态表达式计算(续2)
上两篇废话太多,这一次我就不多说了,由于代码比较简单,可以直接从https://github.com/scottshare/DynamicExpress.git地址下载. 以下说明一下使用方法: Dy ...
- Role Object(角色对象)
Role Object(角色对象) 索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Role Object 的示例实现. 意图 通过明确地附加角色对象到目标对象中,以使对象可以 ...