C#: 导入.导出.解析 txt 、ini 文本文件格式配置文件

说明:程序可配置参数保存为配置文件 config.ini ,介绍的案例实现 修改、保存、调用、解析这些参数。

1.一个简单的配置文件方案,如以下界面参数实现配置文件的操作

以下代码解析如下格式的配置文件,以","为分隔符,左边为 uint 参数 右边为 bool参数,一行为一组数据。

cs 复制代码
1111,True
2212,True
3313,True
4414,True
5515,True
6616,True
7717,True
8717,True
9919,True
1110,True
2110,True
3112,True
1100,True
3,True
cs 复制代码
//txt配置文件读写

// ConfigData 类用于表示配置数据的结构  
public class ConfigData
{
    public uint UIntParam { get; set; } // UIntParam 属性表示一个无符号整型参数 
    public bool BoolParam { get; set; } // BoolParam 属性表示一个布尔型参数  

    //这两个属性都提供了 get 和 set 访问器,这意味着它们可以被读取(获取值)和写入(设置值)。
}

// 配置文件的导入导出
public class ConfigFileManager
{
    private const string name = "config.txt";  //配置文件名
    private const byte Line_Data_Qty = 2;      //一行有几个数据

    public static void ExportConfigFile(ConfigData[] configData)
    {
        string FilePath = "";

        // 获取当前执行程序集的路径  
        // 这个路径将用作配置文件的保存路径的基础 
        string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
        // 获取程序集路径所在的目录  
        string directory = System.IO.Path.GetDirectoryName(path);

        // 使用Path.Combine来确保路径拼接的正确性  
        FilePath = System.IO.Path.Combine(directory, "config.txt");
        // 使用StreamWriter来写入配置文件  
        // StreamWriter会自动处理文件打开、写入和关闭的过程  
        using (StreamWriter writer = new StreamWriter(FilePath))
        {
            // 遍历传入的配置数据数组  
            foreach (var data in configData)
            {
                // 将每个配置数据的UIntParam和BoolParam以逗号分隔写入文件  
                // 并换行,为下一条记录做准备
                writer.WriteLine($"{data.UIntParam},{data.BoolParam}");
            }
        }
    }

    public static ConfigData[] ImportConfigFile()
    {
        string FilePath = "";

        // 获取当前执行程序集的路径  
        // 这个路径作为配置文件的保存路径  
        string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
        // 获取程序集路径所在的目录  
        string directory = System.IO.Path.GetDirectoryName(path);

        // 使用Path.Combine来确保路径拼接的正确性  
        FilePath = System.IO.Path.Combine(directory, "config.txt");
        // 检查配置文件是否存在  
        if (!File.Exists(FilePath))
        {
            throw new FileNotFoundException("没有找到配置文件."); // 如果配置文件不存在,则抛出异常
        }

        string[] lines = File.ReadAllLines(FilePath);           // 读取配置文件的所有行
        ConfigData[] configData = new ConfigData[lines.Length]; // 创建一个与行数相同长度的ConfigData数组

        for (int i = 0; i < lines.Length; i++)
        {
            string[] values = lines[i].Split(','); // 将每一行按逗号分隔成多个值

            if (values.Length != Line_Data_Qty)    // 检查是否每行都包含两个值  
            {
                throw new FormatException($"第 {i + 1} 行的格式不正确");      // 如果分隔后的值数量不等于 Line_Data_Qty,则抛出异常
            }
            // 定义用于存储解析结果的变量 
            uint uintParam;
            bool boolParam;

            if (!uint.TryParse(values[0], out uintParam))                           // 尝试将第一个值解析为无符号整数
            {
                throw new FormatException($"第 {i + 1} 行的无符号整数值不正确");  // 如果解析失败,则抛出异常
            }

            if (!bool.TryParse(values[1], out boolParam))                           // 尝试将第二个值解析为布尔值
            {
                throw new FormatException($"第 {i + 1} 行的布尔值不正确");        // 如果解析失败,则抛出异常
            }

            configData[i] = new ConfigData // 创建一个新的ConfigData对象,并将解析后的值赋给它
            {
                UIntParam = uintParam,
                BoolParam = boolParam
            };
        }

        return configData; // 返回填充了配置数据的数组
    }
}

//导入按钮
private void button_Res_List_Cfg_Input_Click(object sender, EventArgs e)
{
    // 导入配置文件
    ConfigData[] configData = new ConfigData[14];
    for (int i = 0; i < configData.Length; i++)
    {
        configData[i] = new ConfigData();
    }
    configData = ConfigFileManager.ImportConfigFile();

    textBox_Res_List1.Text = configData[0].UIntParam.ToString();
    textBox_Res_List2.Text = configData[1].UIntParam.ToString();
    textBox_Res_List3.Text = configData[2].UIntParam.ToString();
    textBox_Res_List4.Text = configData[3].UIntParam.ToString();
    textBox_Res_List5.Text = configData[4].UIntParam.ToString();
    textBox_Res_List6.Text = configData[5].UIntParam.ToString();
    textBox_Res_List7.Text = configData[6].UIntParam.ToString();
    textBox_Res_List8.Text = configData[7].UIntParam.ToString();
    textBox_Res_List9.Text = configData[8].UIntParam.ToString();
    textBox_Res_List10.Text = configData[9].UIntParam.ToString();
    textBox_Res_List11.Text = configData[10].UIntParam.ToString();
    textBox_Res_List12.Text = configData[11].UIntParam.ToString();

    textBox_Res_List_Time.Text = configData[12].UIntParam.ToString();
    textBox_Res_List_Count.Text = configData[13].UIntParam.ToString();
    textBox_Res_List_Count_Surplus.Text = configData[13].UIntParam.ToString();

    checkBox_Res_List1.Checked = configData[0].BoolParam;
    checkBox_Res_List2.Checked = configData[1].BoolParam;
    checkBox_Res_List3.Checked = configData[2].BoolParam;
    checkBox_Res_List4.Checked = configData[3].BoolParam;
    checkBox_Res_List5.Checked = configData[4].BoolParam;
    checkBox_Res_List6.Checked = configData[5].BoolParam;
    checkBox_Res_List7.Checked = configData[6].BoolParam;
    checkBox_Res_List8.Checked = configData[7].BoolParam;
    checkBox_Res_List9.Checked = configData[8].BoolParam;
    checkBox_Res_List10.Checked = configData[9].BoolParam;
    checkBox_Res_List11.Checked = configData[10].BoolParam;
    checkBox_Res_List12.Checked = configData[11].BoolParam;
    MessageBox.Show("导入成功");
}

//保存按钮
private void button_Res_List_Cfg_Save_Click(object sender, EventArgs e)
{
    // 导出配置文件
    ConfigData[] configData = new ConfigData[14];
    for (int i = 0; i < configData.Length; i++)
    {
        configData[i] = new ConfigData();
    }

    configData[0].BoolParam = checkBox_Res_List1.Checked;
    configData[1].BoolParam = checkBox_Res_List2.Checked;
    configData[2].BoolParam = checkBox_Res_List3.Checked;
    configData[3].BoolParam = checkBox_Res_List4.Checked;
    configData[4].BoolParam = checkBox_Res_List5.Checked;
    configData[5].BoolParam = checkBox_Res_List6.Checked;
    configData[6].BoolParam = checkBox_Res_List7.Checked;
    configData[7].BoolParam = checkBox_Res_List8.Checked;
    configData[8].BoolParam = checkBox_Res_List9.Checked;
    configData[9].BoolParam = checkBox_Res_List10.Checked;
    configData[10].BoolParam = checkBox_Res_List11.Checked;
    configData[11].BoolParam = checkBox_Res_List12.Checked;

    configData[12].BoolParam = true;
    configData[13].BoolParam = true;

    try
    {
        configData[0].UIntParam = Convert.ToUInt32(textBox_Res_List1.Text);
        configData[1].UIntParam = Convert.ToUInt32(textBox_Res_List2.Text);
        configData[2].UIntParam = Convert.ToUInt32(textBox_Res_List3.Text);
        configData[3].UIntParam = Convert.ToUInt32(textBox_Res_List4.Text);
        configData[4].UIntParam = Convert.ToUInt32(textBox_Res_List5.Text);
        configData[5].UIntParam = Convert.ToUInt32(textBox_Res_List6.Text);
        configData[6].UIntParam = Convert.ToUInt32(textBox_Res_List7.Text);
        configData[7].UIntParam = Convert.ToUInt32(textBox_Res_List8.Text);
        configData[8].UIntParam = Convert.ToUInt32(textBox_Res_List9.Text);
        configData[9].UIntParam = Convert.ToUInt32(textBox_Res_List10.Text);
        configData[10].UIntParam = Convert.ToUInt32(textBox_Res_List11.Text);
        configData[11].UIntParam = Convert.ToUInt32(textBox_Res_List12.Text);

        configData[12].UIntParam = Convert.ToUInt32(textBox_Res_List_Time.Text);
        configData[13].UIntParam = Convert.ToUInt32(textBox_Res_List_Count.Text);
    }
    catch (Exception)
    {
        MessageBox.Show("数据输入错误", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        return;
    }

    ConfigFileManager.ExportConfigFile(configData);
    MessageBox.Show("保存成功");
}

2.数组类型数据配置文件解析,可支持注释内容

以下代码是实现一个对如下配置文件的解析和读写功能

cs 复制代码
#注释1
[CfgFileArray_1]
1=0,3000
2=0,1000

#注释2
[CfgFileArray_2]
1=10000,20
2=44000,20

#注释3
[CfgFileArray_3]
1=1500,20
2=3300,20

#注释4
[CfgFileArray_4]
1=888,3000
2=5000,1000
3=20000,1000
4=40000,1000
5=60000,1000
6=80000,1000
7=100000,1000
8=120000,1000

#注释5
[CfgFileArray_5]
1=800,3000
2=1000,1000
3=2500,1000
4=3650,1000
5=4200,1000
6=5000,1000

#注释6
[CfgFileArray_6]
1=1480,5000
2=2945,1000
3=4985,1000

#注释7
[CfgFileArray_7]
0=65550001,3001
1=65550001,3001
2=65550002,3002
3=65550003,3003
4=65550004,3004

代码

cs 复制代码
public class ConfigFileManager2
{
    /// <summary>  
    /// 解析配置文件,并返回配置数据和注释。  
    /// </summary>  
    /// <param name="filePath">配置文件的路径。</param>  
    /// <returns>一个包含配置数据和注释的元组。</returns>  
    public (Dictionary<string, Dictionary<int, string>> ConfigData, Dictionary<string, List<string>> Comments) ParseConfigFile(string filePath)
    {
        // 初始化配置数据的字典,键为节名称,值为包含键值对的字典  
        var configData = new Dictionary<string, Dictionary<int, string>>();
        // 初始化注释的字典,键为节名称,值为包含注释的列表  
        var comments = new Dictionary<string, List<string>>();
        // 存储当前正在处理的节的名称  
        var section = string.Empty;
        // 存储当前节的注释列表  
        var currentComments = new List<string>();

        try
        {
            // 读取配置文件的所有行  
            var lines = File.ReadAllLines(filePath);
            foreach (var line in lines)
            {
                // 检查当前行是否为一个节的开始  
                if (line.StartsWith("[") && line.EndsWith("]"))
                {
                    // 提取节名称,并去除两端的方括号  
                    section = line.Trim('[', ']');
                    // 如果配置数据中尚未包含该节,则添加新节  
                    if (!configData.ContainsKey(section))
                    {
                        configData[section] = new Dictionary<int, string>();
                    }

                    // 如果有当前节的注释,则添加到注释字典中  
                    // Add comments for the new section (if any)    
                    if (currentComments.Any())
                    {
                        comments[section] = currentComments;
                        currentComments = new List<string>(); // 重置当前节的注释列表  
                    }
                }
                // 检查当前行是否为一个注释行  
                else if (line.StartsWith("#"))
                {
                    // 将注释添加到当前节的注释列表中  
                    // Add comment to current section    
                    currentComments.Add(line);
                }
                // 检查当前行是否为一个有效的键值对  
                else if (!string.IsNullOrWhiteSpace(line))
                {
                    // 使用等号分割键值对  
                    var parts = line.Split('=');
                    if (parts.Length == 2)
                    {
                        // 尝试将键解析为整数  
                        if (int.TryParse(parts[0].Trim(), out int key))
                        {
                            // 将键值对添加到当前节的配置数据中  
                            configData[section][key] = parts[1].Trim();
                        }
                    }
                }
            }

            // 如果有最后一个节的注释,则添加到注释字典中  
            // Add comments for the last section (if any)    
            if (currentComments.Any())
            {
                comments[section] = currentComments;
            }
        }
        catch (Exception ex)
        {
            // 如果发生异常,则输出异常信息  
            Console.WriteLine("Error parsing the configuration file: " + ex.Message);
        }

        // 返回包含配置数据和注释的元组  
        return (configData, comments);
    }


    /// <summary>  
    /// 将配置数据和注释写入到指定的配置文件中。  
    /// </summary>  
    /// <param name="filePath">配置文件的路径。</param>  
    /// <param name="configData">包含配置数据的字典,键为节名称,值为包含键值对的字典。</param>  
    /// <param name="comments">包含注释的字典,键为节名称,值为包含注释列表的列表。</param>  
    public void WriteConfigFile(string filePath, Dictionary<string, Dictionary<int, string>> configData, Dictionary<string, List<string>> comments)
    {
        // 创建一个StringBuilder对象,用于构建配置文件的内容  
        var sb = new StringBuilder();

        // 遍历配置数据中的每一个节  
        foreach (var section in configData)
        {
            // 尝试获取该节的注释  
            // Write comments for this section    
            if (comments.TryGetValue(section.Key, out var sectionComments))
            {
                // 遍历该节的每一条注释  
                foreach (var comment in sectionComments)
                {
                    // 将注释写入到StringBuilder中  
                    sb.AppendLine(comment);
                }
            }

            // 写入节标题  
            sb.AppendLine("[" + section.Key + "]");

            // 遍历该节下的每一个键值对  
            foreach (var item in section.Value)
            {
                // 将键值对写入到StringBuilder中,格式为"键=值"  
                sb.AppendLine(item.Key + "=" + item.Value);
            }

            // 在节与节之间添加一个空行  
            sb.AppendLine(); // Empty line between sections    
        }

        try
        {
            // 将StringBuilder中的内容写入到指定的配置文件中  
            File.WriteAllText(filePath, sb.ToString());
        }
        catch (Exception ex)
        {
            // 如果写入文件时发生异常,则捕获异常并输出错误信息  
            Console.WriteLine("Error writing the configuration file: " + ex.Message);
        }
    }

    // 写入配置文件中的某个值  
    public void SetConfigValue(Dictionary<string, Dictionary<int, string>> configData, string section, int key, string value)
    {
        // 检查configData字典是否包含指定的配置节section  
        if (configData.ContainsKey(section))
        {
            // 如果包含,则直接在该配置节的字典中设置或更新配置项的值  
            configData[section][key] = value;
        }
        else
        {
            // 如果不包含,则先创建一个新的字典,并添加到configData中作为该配置节对应的字典  
            configData[section] = new Dictionary<int, string>();
            // 接着在新创建的字典中设置配置项的值  
            configData[section][key] = value;
        }
    }

    // 读取配置文件中的某个值  
    public string GetConfigValue(Dictionary<string, Dictionary<int, string>> configData, string section, int key)
    {
        // 判断configData字典中是否包含指定的配置节section  
        if (configData.ContainsKey(section) &&
            // 判断该配置节对应的字典中是否包含指定的配置项key  
            configData[section].ContainsKey(key))
        {
            // 如果都包含,则返回该配置项的值  
            return configData[section][key];
        }

        // 如果configData字典中不包含指定的配置节section,或者该配置节对应的字典中不包含指定的配置项key,则返回null  
        return null;
    }
}

//应用测试代码
private void button_test_Click(object sender, EventArgs e)
{
    string filePath = "config.ini"; // 替换为你的配置文件路径  
    var ConfigFileManager2 = new ConfigFileManager2();

    try
    {
        // 解析配置文件  
        var (configData, comments) = ConfigFileManager2.ParseConfigFile(filePath);

        // 读取配置文件中的值
        for (int i = 0; i < configData["CfgFileArray_7"].Count; i++) //遍历一个项目中所有数据
        {
            string CfgFileArray = ConfigFileManager2.GetConfigValue(configData, "CfgFileArray_7", i);
           //if (string.IsNullOrEmpty(CfgFileArray))  //判断是否为空,空则退出循环
           //{ continue; }
            Console.WriteLine("Current DAC Parameter: " + CfgFileArray);
        }


        // 在这里,你可以对configData和comments进行操作...  
        // 修改配置文件中的值
        ConfigFileManager2.SetConfigValue(configData, "CfgFileArray_7", 1, "65550001,3001");
        ConfigFileManager2.SetConfigValue(configData, "CfgFileArray_7", 2, "65550002,3002");
        ConfigFileManager2.SetConfigValue(configData, "CfgFileArray_7", 3, "65550003,3003");
        ConfigFileManager2.SetConfigValue(configData, "CfgFileArray_7", 4, "65550004,3004");

        // 将修改后的配置写回文件  
        ConfigFileManager2.WriteConfigFile(filePath, configData, comments);
    }
    catch (Exception ex)
    {
        Console.WriteLine("An error occurred: " + ex.Message);
    }
}
相关推荐
Zԅ(¯ㅂ¯ԅ)6 小时前
C#桌面应用制作计算器
c#
shepherd枸杞泡茶7 小时前
WPF动画
c#·.net·wpf
code_shenbing7 小时前
跨平台WPF框架Avalonia教程 三
前端·microsoft·ui·c#·wpf·跨平台·界面设计
三天不学习8 小时前
C# AutoMapper 10个常用方法总结
c#·automapper·对象映射
oioihoii8 小时前
单例模式详解
c++·单例模式·c#·大学必学
suzh1qian10 小时前
Unity类银河战士恶魔城学习总结(P133 Merge skill tree with Parry skill把技能树和格挡技能相组合)
学习·unity·c#·游戏引擎
sukalot10 小时前
windows C#-异步编程模型(下)
开发语言·windows·c#
zls36536511 小时前
C#开发最快的浏览器,打造极速浏览体验
开发语言·c#
闲人编程13 小时前
Hadoop 使用过程中 15 个常见问题的详细描述、解决方案
大数据·hadoop·eclipse·解决方案·yarn·配置文件
战族狼魂14 小时前
C#的数据类型总结:decimal ,double,float的区别
开发语言·c#