前言

最近由于项目需求,需要读写操作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 = ; 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[]; //默认第一个类为主体类,主体类的属性为其他类
var tt = XmlClass.GetType();
for (int i = ; 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[]; //默认第一个类为主体类 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文件读写操作(依然带干货)的更多相关文章

  1. 实现动态的XML文件读写操作

    实现动态的XML文件读写操作(依然带干货) 前言 最近由于项目需求,需要读写操作XML文件,并且存储的XML文件格式会随着导入的数据不同而随时改变(当然导入的数据还是有一定约束的),这样我们要预先定义 ...

  2. ios 简单的plist文件读写操作(Document和NSUserDefaults)

    最近遇到ios上文件读写操作的有关知识,记录下来,以便以后查阅,同时分享与大家. 一,简单介绍一下常用的plist文件. 全名是:Property List,属性列表文件,它是一种用来存储串行化后的对 ...

  3. QXmlStreamReader/QXmlStreamWriter实现Qt下xml文件读写

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QXmlStreamReader/QXmlStreamWriter实现Qt下xml文件读写   ...

  4. c语言文件读写操作总结

    C语言文件读写操作总结 C语言文件操作 一.标准文件的读写 1.文件的打开 fopen() 文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程 ...

  5. [转]Android - 文件读写操作 总结

     转自:http://blog.csdn.net/ztp800201/article/details/7322110 Android - 文件读写操作 总结 分类: Android2012-03-05 ...

  6. PHP文件读写操作之文件写入代码

    在PHP网站开发中,存储数据通常有两种方式,一种以文本文件方式存储,比如txt文件,一种是以数据库方式存储,比如Mysql,相对于数据库存储,文件存储并没有什么优势,但是文件读写操作在基本的PHP开发 ...

  7. 更新java对xml文件的操作

    //更新java在xml文件中操作的内容 public static void upda(Document doc) throws Exception{ //创建一个TransformerFactor ...

  8. Java 字节流实现文件读写操作(InputStream-OutputStream)

    Java 字节流实现文件读写操作(InputStream-OutputStream) 备注:字节流比字符流底层,但是效率底下. 字符流地址:http://pengyan5945.iteye.com/b ...

  9. Java 字符流实现文件读写操作(FileReader-FileWriter)

    Java 字符流实现文件读写操作(FileReader-FileWriter) 备注:字符流效率高,但是没有字节流底层 字节流地址:http://pengyan5945.iteye.com/blog/ ...

随机推荐

  1. 关于LDA的文章

    转:http://www.zhizhihu.com/html/y2011/3228.html l  Theory n  Introduction u  Unsupervised learning by ...

  2. Maven高级应用--编译全模块包-dist包

    1. 在需要生成dist包的模块级别,新建文件夹xxx-xxxx-dist 2. 进入目录,新建pom.xml,建议copy 3. dependencies节点,把要编译成全局包的应用引入进来 < ...

  3. 解析csv数据导入mysql的方法

    mysql自己有个csv引擎,可以通过这个引擎来实现将csv中的数据导入到mysql数据库中,并且速度比通过php或是python写的批处理程序快的多. 具体的实现代码示例: 代码如下: load d ...

  4. 全链路实践Spring Cloud 微服务架构

    Spring Cloud 微服务架构全链路实践Spring Cloud 微服务架构全链路实践 阅读目录: 网关请求流程 Eureka 服务治理 Config 配置中心 Hystrix 监控 服务调用链 ...

  5. mongodb 副本集+分片集群搭建

    数据分片节点#192.168.114.26mongod --shardsvr --replSet rsguo --port 2011 --dbpath=/data/mongodb/guo --logp ...

  6. AngularJs学习笔记--Understanding Angular Templates

    原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model angular template是一个声明规范,与mode ...

  7. selenium+java项目实战---百度输入框

    最近对java+selenium+testng+maven 做一个小项目的总结,并对工作中的框架在做一些小总结,大概目录为: 1.项目实战--百度登录输入框 2.项目的二次封装 3.框架分层,及po模 ...

  8. dom4j.jar有什么作用?

    om4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源代 ...

  9. 简单使用Spring Boot+JpaRepository+hibernate搭建项目

    sql: -- -------------------------------------------------------- -- 主机: 127.0.0.1 -- 服务器版本: 10.3.9-M ...

  10. 用Java+xml配置方式实现Spring数据事务(编程式事务)

    一.用Java配置的方式 1.实体类: Role public class Role { private int id; private String roleName; private String ...