常见的配置文件Ini,Json,Xml比较:
优点 | 缺点 | |
Json | 可以被JS原生解析 应用广泛,适合于数据交换处理,被于WEB和移动应用开发,所以服务端与客户端一般被要求同时支持JSON 数据量小,易于解析,因为格式简单,只有数组,对象和普通文本 | 肉眼可读性差, 字符类型与数值类型容易混淆 |
Xml | 扩展性好,标记自由定义,互操作性强,规范统一 支持嵌套 | 数据量大,重复信息最多,因为嵌套结点必须有头和尾,每一个节点的属性都必须有键有值,... 解析最复杂,因为格式本身复杂,有多种类型的节点 |
Ini | 数据量小,格式最简单 解析最简单,只要解析[],=,换行 支持注释 ; | ini只支持键值模式,结构只有2层,无嵌套。很难扩展多层。 有64kb的大小限制 |
新建IntegratedOperateConfigFileDemo窗体应用程序(.net 4.5)
将默认的Form1窗体重命名为 FormIntegratedOperateConfigFile,放上三个树图TreeView控件tvDataIni、tvDataJson、tvDataXml。窗体设计如下:
一、新建类IniFileUtil.cs,用于读写Ini配置文件,源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Collections.Specialized;
namespace IntegratedOperateConfigFileDemo
{
public class IniFileUtil
{
/// <summary>
/// 读取ini文件的键值对
/// </summary>
/// <param name="lpAppName">段落名,示例:[Segment]</param>
/// <param name="lpKeyName">键名:Key=Value的Key</param>
/// <param name="lpDefault">默认值</param>
/// <param name="lpReturnedString">值:Key=Value的Value</param>
/// <param name="nSize">最大长度</param>
/// <param name="lpFileName">ini文件的全路径</param>
/// <returns></returns>
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);
/// <summary>
/// 读取ini文件的键值对,使用字节数组
/// </summary>
/// <param name="section"></param>
/// <param name="key"></param>
/// <param name="def"></param>
/// <param name="retVal"></param>
/// <param name="size"></param>
/// <param name="filePath"></param>
/// <returns></returns>
[DllImport("kernel32")]
public static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath);
/// <summary>
/// 写ini文件
/// </summary>
/// <param name="section">要写入的段落名</param>
/// <param name="key">要写入的键,如果该key存在则覆盖写入</param>
/// <param name="val">键所对应的值</param>
/// <param name="filePath">ini文件的完整路径和文件名</param>
/// <returns></returns>
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int WritePrivateProfileString(string section, string key, string val, string filePath);
/// <summary>
/// 读取一个段落,返回键值对集合
/// </summary>
/// <param name="section"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public static NameValueCollection ReadSegemnt(string section, string fileName)
{
NameValueCollection nameValueCollection = new NameValueCollection();
byte[] buffer = new byte[16384];
int length = GetPrivateProfileString(section, null, null, buffer, buffer.GetUpperBound(0), fileName);
//获取某个段落下的所有key
StringCollection sc = new StringCollection();
int index = 0;
int from = 0;
while (index < length)
{
if (buffer[index] == 0 && index > from)
{
sc.Add(Encoding.GetEncoding("gbk").GetString(buffer, from, index - from));
from = index + 1;
}
index++;
}
StringBuilder sb;
for (int i = 0; i < sc.Count; i++)
{
sb = new StringBuilder();
GetPrivateProfileString(section, sc[i], "", sb, 2048, fileName);
nameValueCollection[sc[i]] = sb.ToString();
}
return nameValueCollection;
}
}
}
二、新建Json相关联类TestJsonClass.cs,源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IntegratedOperateConfigFileDemo
{
/// <summary>
/// 测试Json相关类
/// </summary>
public class TestJsonClass
{
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 电话
/// </summary>
public string Phone { get; set; }
}
}
三、窗体FormIntegratedOperateConfigFile的主要代码(忽略设计器代码)。
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Xml;
namespace IntegratedOperateConfigFileDemo
{
public partial class FormIntegratedOperateConfigFile : Form
{
public FormIntegratedOperateConfigFile()
{
InitializeComponent();
DoubleBuffered = true;
}
protected override void WndProc(ref Message m)
{
//减少树图控件的闪烁:禁掉清除背景消息WM_ERASEBKGND
if (m.Msg == 0x0014)
{
return;
}
base.WndProc(ref m);
}
private void FormIntegratedOperateConfigFile_Load(object sender, EventArgs e)
{
string fileName = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
AddSegemntToTree("BasicConfig", fileName);
AddSegemntToTree("AA", fileName);
AddSegemntToTree("TcpClient", fileName);
AddSegemntToTree("ComConfig", fileName);
tvDataIni.ExpandAll();
string jsonFile = AppDomain.CurrentDomain.BaseDirectory + "config.json";
AddJsonToTree(jsonFile);
tvDataJson.ExpandAll();
string xmlFile = AppDomain.CurrentDomain.BaseDirectory + "config.xml";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(xmlFile);
XmlNode rootNode = xmlDocument.DocumentElement;
TreeNode treeNode = new TreeNode($"{rootNode.Name}【类型:{rootNode.NodeType}】");
BindXml(treeNode.Nodes, rootNode);
tvDataXml.Nodes.Add(treeNode);
tvDataXml.ExpandAll();
}
/// <summary>
/// 递归方法
/// 思路: 1.查看node下的所有子节点
/// 2.将子节点绑定到TreeNode上,如果子节点存在属性,将属性页显示出来
/// 3.如果subNode存在子节点继续递归遍历
/// </summary>
/// <param name="nodes">树节点集合</param>
/// <param name="node">XML的一个节点</param>
private void BindXml(TreeNodeCollection nodes, XmlNode node)
{
foreach (XmlNode subNode in node.ChildNodes)
{
string text = "";
if (subNode.Value == null) //如果节点值不存在
{
if (subNode.Attributes != null && subNode.Attributes.Count > 0)
{
text += subNode.Name + "--属性有:";
for (int i = 0; i < subNode.Attributes.Count; i++)
{
text += subNode.Attributes[i].Name + ":" + subNode.Attributes[i].Value + " ";
}
}
else //节点没有属性
{
text = subNode.Name;
}
}
else //如果节点值存在
{
//注释的特殊处理
if (subNode.NodeType == XmlNodeType.Comment)
{
text = "【注释】" + subNode.Value;
}
else
{
text = subNode.Value;
}
}
//忽略 回车、换行、空格等文本
if (text.Trim().Length > 0)
{
TreeNode tempNode = new TreeNode(text);
nodes.Add(tempNode);//如果节点存在子节点
if (subNode.HasChildNodes)
{
BindXml(tempNode.Nodes, subNode);//这里递归
}
}
}
}
private void AddJsonToTree(string jsonFile)
{
string jsonString = File.ReadAllText(jsonFile, System.Text.Encoding.GetEncoding("gbk"));
//需要添加对System.Web的引用
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, List<TestJsonClass>> dictList = serializer.Deserialize<Dictionary<string, List<TestJsonClass>>>(jsonString);
for (int i = 0; i < dictList.Count; i++)
{
KeyValuePair<string, List<TestJsonClass>> keyValuePair = dictList.ElementAt(i);
string key = keyValuePair.Key;
TreeNode node = new TreeNode(key);
List<TestJsonClass> list = keyValuePair.Value;
for (int j = 0; j < list.Count; j++)
{
TreeNode arrayNode = new TreeNode($"TestJsonClass[{j}]");
arrayNode.Nodes.Add($"Id:{list[j].Id}");
arrayNode.Nodes.Add($"Name:{list[j].Name}");
arrayNode.Nodes.Add($"Phone:{list[j].Phone}");
node.Nodes.Add(arrayNode);
}
tvDataJson.Nodes.Add(node);
}
}
private void AddSegemntToTree(string section, string fileName)
{
NameValueCollection nvc = IniFileUtil.ReadSegemnt(section, fileName);
TreeNode node = new TreeNode(section);
foreach (string key in nvc.AllKeys)
{
node.Nodes.Add($"{key}:{nvc[key]}");
}
//忽略段落不存在的情况
if (nvc.Count > 0)
{
tvDataIni.Nodes.Add(node);
}
}
}
}
四、三个测试文件的具体内容
设置: 文件属性---》复制到输出目录---》始终复制
1).config.ini文件
[BasicConfig]
AutoLogin=1
EnableVision=1
EnableMeasure=0
WorkCategory=键合机
[TcpClient]
Enabled=1
ServerIp=127.0.0.1
Port=1234
[ComConfig]
Enabled=1
PortName=Com1
BaudRate=115200
2).config.json文件
{
"Root": [
{
"Id": 1,
"Name": "张三",
"Phone": "12345678910"
},
{
"Id": 3,
"Name": "李四",
"Phone": "98765432100"
},
{
"Id": 4,
"Name": "王五",
"Phone": "77884455216"
}
]
}
3).config.xml文件
<?xml version="1.0" encoding="utf-8" ?>
<Root>
<InboundForMes>
<!--是否启用-->
<Enabled>1</Enabled>
<User>Admin</User>
<TimeOut>3000</TimeOut>
<!--超时允许重新调用次数-->
<AllowTimeOutCount>1</AllowTimeOutCount>
<Site>2002</Site>
<Operation>BUSWLD</Operation>
</InboundForMes>
<OutboundForMes>
<!--是否启用-->
<Enabled>1</Enabled>
<User>Hello</User>
<TimeOut>8000</TimeOut>
<Site>2002</Site>
<Resource>MLWM006X</Resource>
<!--出站时自定义相关上传数据-->
<ParametricData EnglishName="SCGL1" FieldName="Power_1" MappingName="Power_1" ChineseName="输出功率1" DataType="NUMBER" Value="0" />
<ParametricData EnglishName="SCGL2" FieldName="Power_2" MappingName="Power_2" ChineseName="输出功率2" DataType="NUMBER" Value="0" />
<ParametricData EnglishName="SCGL3" FieldName="Power_3" MappingName="Power_3" ChineseName="输出功率3" DataType="NUMBER" Value="0" />
<ParametricData EnglishName="LJL1" FieldName="Defocus" MappingName="Defocus_1" ChineseName="离焦量" DataType="NUMBER" Value="0" />
<ParametricData EnglishName="JJH" FieldName="FixtureNo" MappingName="FixtureNo" ChineseName="夹具号" DataType="NUMBER" Value="0" />
</OutboundForMes>
</Root>
五、程序运行如图: