说明:程序可配置参数保存为配置文件 config.ini ,介绍的案例实现 修改、保存、调用、解析这些参数。
1.一个简单的配置文件方案,如以下界面参数实现配置文件的操作
以下代码解析如下格式的配置文件,以“,”为分隔符,左边为 uint 参数 右边为 bool参数,一行为一组数据。
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
//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.数组类型数据配置文件解析,可支持注释内容
以下代码是实现一个对如下配置文件的解析和读写功能
#注释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
代码
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);
}
}