C#读取配置文件Ini,json,xml并绑定到树图上

83 篇文章 3 订阅

常见的配置文件Ini,Json,Xml比较:

 优点缺点
Json可以被JS原生解析
应用广泛,适合于数据交换处理,被于WEB和移动应用开发,所以服务端与客户端一般被要求同时支持JSON
数据量小,易于解析,因为格式简单,只有数组,对象和普通文本
肉眼可读性差,
字符类型与数值类型容易混淆
Xml

扩展性好,标记自由定义,互操作性强,规范统一
被广泛使用(HTML,SOAP,应用的界面布局结构如安卓)
描述性好,有节点名,属性名,还有文件头(描述字符编码和版本)

支持嵌套
支持注释<!---->
支持特殊格式,CDATA,<![CDATA[文本内容]]>

数据量大,重复信息最多,因为嵌套结点必须有头和尾,每一个节点的属性都必须有键有值,...
解析最复杂,因为格式本身复杂,有多种类型的节点
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>


五、程序运行如图:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值