- 动态设置配置文件读取哪个文件,并支持替换某个配置项的值
- 配置文件修改了内容,支持实时读取配置项值
目录
读取配置文件帮助类【推荐】,默认相对路径,高性能,
//功用:读取配置文件值
//创建时间:2022-1-4 16:14:35
//作者:王浩力
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ConsoleMain.Model
{
/// <summary>
/// 读取配置文件值
/// </summary>
public static class MyConfigReader
{
/// <summary>
/// 配置文件内容
/// </summary>
private static readonly string configContent;
///// <summary>
///// 配置文件路径
///// </summary>
//private static readonly string fileConfig = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sysData.ini");
#if PRODUCTION
//生产环境,
/// <summary>
/// 配置文件路径
/// </summary>
private static readonly string fileConfig = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sysData.ini");
#else
//测试环境
/// <summary>
/// 配置文件路径
/// </summary>
private static readonly string fileConfig = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sysData_test.ini");
#endif
/// <summary>
/// 实时配置文件内容
/// </summary>
private static string realTimeConfigContent;
/// <summary>
/// 实时配置文件最后修改时间
/// </summary>
private static DateTime realTimeConfigLastWriteTimeUtc;
/// <summary>
/// 实时配置读取锁
/// </summary>
private static readonly object realTimeConfigLock = new object();
static MyConfigReader()
{
Console.WriteLine($"当前使用配置文件:{fileConfig}");
//读取自定义配置文件 sysData.ini
configContent = CleanConfigContent(System.IO.File.ReadAllText(fileConfig));
realTimeConfigContent = configContent;
realTimeConfigLastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
}
/// <summary>
/// 清理配置文件内容里面的注释,移除整行注释、行尾注释和空白行
/// </summary>
/// <param name="content">原始配置内容</param>
/// <returns>清理后的配置内容</returns>
private static string CleanConfigContent(string content)
{
if (string.IsNullOrEmpty(content))
{
return string.Empty;
}
//移除#开头的所有行, 去掉注释行
Regex regular = new Regex("^\\s*#\\s*.*", RegexOptions.Multiline);
content = regular.Replace(content, "");
//移除空白行
Regex regular2 = new Regex("^\\s*", RegexOptions.Multiline);
content = regular2.Replace(content, "");
System.Text.StringBuilder builder = new System.Text.StringBuilder();
using (System.IO.StringReader reader = new System.IO.StringReader(content))
{
string line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length == 0)
{
continue;
}
if (line.StartsWith("#"))
{
continue;
}
if (line.IndexOf('<') >= 0 || line.IndexOf('>') >= 0 || line.IndexOf('[') >= 0 || line.IndexOf(']') >= 0)
{
builder.AppendLine(line);
continue;
}
int keyEndIndex = -1;
for (int i = 0; i < line.Length; i++)
{
if (char.IsWhiteSpace(line[i]))
{
keyEndIndex = i;
break;
}
}
if (keyEndIndex < 0)
{
builder.AppendLine(line); //处理[]包扩的行数据;
continue;
}
string key = line.Substring(0, keyEndIndex).Trim();//参数名称
string valuePart = line.Substring(keyEndIndex).TrimStart();
if (valuePart.Length == 0)
{
builder.AppendLine(key);
continue;
}
// 单行配置的注释只在值内容之后生效,允许值本身以 # 开头,例如 #FFFFFF
int commentIndex = -1;
Regex regex = new Regex(@"\s");
if (regex.IsMatch(valuePart))
{
commentIndex = regex.Match(valuePart)?.Index ?? 0;
}
if (commentIndex >= 0)
{
valuePart = valuePart.Substring(0, commentIndex).TrimEnd();
}
if (valuePart.Length == 0)
{
builder.AppendLine(key);
continue;
}
builder.AppendLine(key + " " + valuePart);
}
}
return builder.ToString();
}
/// <summary>
/// 读取当前配置文件内容
/// </summary>
/// <returns>返回配置文件内容</returns>
private static string ReadCurrentConfigContent()
{
return CleanConfigContent(System.IO.File.ReadAllText(fileConfig));
}
/// <summary>
/// 获取实时配置文件内容,配置文件修改后自动重新读取
/// </summary>
/// <returns>返回实时配置文件内容</returns>
private static string GetRealTimeConfigContent()
{
DateTime lastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
if (lastWriteTimeUtc == realTimeConfigLastWriteTimeUtc)
{
return realTimeConfigContent;
}
lock (realTimeConfigLock)
{
lastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
if (lastWriteTimeUtc != realTimeConfigLastWriteTimeUtc)
{
realTimeConfigContent = ReadCurrentConfigContent();
realTimeConfigLastWriteTimeUtc = lastWriteTimeUtc;
}
return realTimeConfigContent;
}
}
/// <summary>
/// 读取单行配置文件sysData.ini节点的值
/// </summary>
/// <param name="configName">节点名称</param>
/// <returns>返回节点值</returns>
public static string GetConfigValue(string configName)
{
try
{
//解析配置
Regex regular3 = new Regex($"(?<={configName}).*");
string nodeValue = regular3.Match(configContent).Value;
//获取值移除左右空格
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 实时读取单行配置文件sysData.ini节点的值,配置文件修改后自动重新读取
/// </summary>
/// <param name="configName">节点名称</param>
/// <returns>返回节点值</returns>
public static string? GetConfigValueRealTime(string configName)
{
try
{
string currentConfigContent = GetRealTimeConfigContent();
//解析配置
Regex regular3 = new Regex($"(?<={configName}).*");
string nodeValue = regular3.Match(currentConfigContent).Value;
//获取值移除左右空格
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
//return null;
}
/// <summary>
/// 获取列表配置项
/// </summary>
/// <param name="configName">配置项名称</param>
/// <returns>返回list字符串集合</returns>
public static ReadOnlySpan<string> GetConfigList(string configName)
{
string nodeValue = String.Empty;
try
{
Regex regular5 = new Regex($"(?<=({configName})\\s+\\[)(.*\\n)*(?=])");
string txt = configContent.Substring(configContent.IndexOf(configName));
txt = txt.Substring(0, txt.IndexOf("]") + 1);
nodeValue = regular5.Match(txt).Value;
nodeValue = nodeValue.Trim();
//return nodeValue.Split("\r\n",StringSplitOptions.RemoveEmptyEntries).ToList();
var list = nodeValue.Split(System.Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
return new ReadOnlySpan<string>(list);
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取数组配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 实时获取列表配置项,配置文件修改后自动重新读取
/// </summary>
/// <param name="configName">配置项名称</param>
/// <returns>返回list字符串集合</returns>
public static ReadOnlySpan<string> GetConfigListRealTime(string configName)
{
string nodeValue = String.Empty;
try
{
string currentConfigContent = GetRealTimeConfigContent();
Regex regular5 = new Regex($"(?<=({configName})\\s+\\[)(.*\\n)*(?=])");
string txt = currentConfigContent.Substring(currentConfigContent.IndexOf(configName));
txt = txt.Substring(0, txt.IndexOf("]") + 1);
nodeValue = regular5.Match(txt).Value;
nodeValue = nodeValue.Trim();
//return nodeValue.Split("\r\n",StringSplitOptions.RemoveEmptyEntries).ToList();
var list = nodeValue.Split(System.Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
return new ReadOnlySpan<string>(list);
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取数组配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 读取似xml节点以Long_Text.开头配置里面的多行字符串
/// </summary>
/// <param name="configName">Long_Text.节点名称</param>
/// <returns>返回xml之间配置的值</returns>
public static string GetXml(string configName)
{
//(?<=<Long_Text.wusong>)[\s\S]*(?=</Long_Text.wusong>)
string nodeValue = String.Empty;
try
{
Regex regular5 = new Regex($"(?<=<Long_Text.{configName}>)[\\s\\S]*(?=</Long_Text.{configName}>)");
nodeValue = regular5.Match(configContent).Value;
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 实时读取似xml节点以Long_Text.开头配置里面的多行字符串,配置文件修改后自动重新读取
/// </summary>
/// <param name="configName">Long_Text.节点名称</param>
/// <returns>返回xml之间配置的值</returns>
public static string GetXmlRealTime(string configName)
{
//(?<=<Long_Text.wusong>)[\s\S]*(?=</Long_Text.wusong>)
string nodeValue = String.Empty;
try
{
string currentConfigContent = GetRealTimeConfigContent();
Regex regular5 = new Regex($"(?<=<Long_Text.{configName}>)[\\s\\S]*(?=</Long_Text.{configName}>)");
nodeValue = regular5.Match(currentConfigContent).Value;
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
}
}
}
读取配置文件帮助类【2】,手动设置配置文件路径
//功用:读取配置文件值
//创建时间:2026-6-30 10:16:51
//作者:王浩力
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Schema;
using static System.Net.Mime.MediaTypeNames;
namespace ConsoleMain.Model
{
/// <summary>
/// 读取配置文件值,读取终端验证码、SOCKS5代理信息
/// </summary>
public static class MyConfigReader
{
/// <summary>
/// 配置文件内容
/// </summary>
private static string configContent;
/// <summary>
/// 配置文件路径
/// </summary>
//private static readonly string fileConfig = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sysData.ini");
private static string? fileConfig = null;
/// <summary>
/// 实时配置文件内容
/// </summary>
private static string realTimeConfigContent;
/// <summary>
/// 实时配置文件最后修改时间
/// </summary>
private static DateTime realTimeConfigLastWriteTimeUtc;
/// <summary>
/// 实时配置读取锁
/// </summary>
private static readonly object realTimeConfigLock = new object();
public static void Init(string filePath)
{
try
{
//if (fileConfig == null)
//{
fileConfig = filePath;
// 读取自定义配置文件 sysData.ini
configContent = CleanConfigContent(System.IO.File.ReadAllText(fileConfig));
realTimeConfigContent = configContent;
realTimeConfigLastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
//}
}
catch (Exception ex)
{
LogHelpter.AddLog($"配置文件{filePath}初始化失败,{ex.ToString()}", fileNamePrefix: "error");
throw;
}
}
//static MyConfigReaderVerifyCode()
//{
// //读取自定义配置文件 sysData.ini
// configContent = CleanConfigContent(System.IO.File.ReadAllText(fileConfig));
// realTimeConfigContent = configContent;
// realTimeConfigLastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
//}
/// <summary>
/// 清理配置文件内容里面的注释,移除整行注释、行尾注释和空白行
/// </summary>
/// <param name="content">原始配置内容</param>
/// <returns>清理后的配置内容</returns>
private static string CleanConfigContent(string content)
{
if (string.IsNullOrEmpty(content))
{
return string.Empty;
}
//移除#开头的所有行, 去掉注释行
Regex regular = new Regex("^\\s*#\\s*.*", RegexOptions.Multiline);
content = regular.Replace(content, "");
//移除空白行
Regex regular2 = new Regex("^\\s*", RegexOptions.Multiline);
content = regular2.Replace(content, "");
System.Text.StringBuilder builder = new System.Text.StringBuilder();
using (System.IO.StringReader reader = new System.IO.StringReader(content))
{
string line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length == 0)
{
continue;
}
if (line.StartsWith("#"))
{
continue;
}
if (line.IndexOf('<') >= 0 || line.IndexOf('>') >= 0 || line.IndexOf('[') >= 0 || line.IndexOf(']') >= 0)
{
builder.AppendLine(line);
continue;
}
int keyEndIndex = -1;
for (int i = 0; i < line.Length; i++)
{
if (char.IsWhiteSpace(line[i]))
{
keyEndIndex = i;
break;
}
}
if (keyEndIndex < 0)
{
builder.AppendLine(line); //处理[]包扩的行数据;
continue;
}
string key = line.Substring(0, keyEndIndex).Trim();//参数名称
string valuePart = line.Substring(keyEndIndex).TrimStart();
if (valuePart.Length == 0)
{
builder.AppendLine(key);
continue;
}
// 单行配置的注释只在值内容之后生效,允许值本身以 # 开头,例如 #FFFFFF
int commentIndex = -1;
Regex regex = new Regex(@"\s");
if (regex.IsMatch(valuePart))
{
commentIndex = regex.Match(valuePart)?.Index ?? 0;
}
if (commentIndex >= 0)
{
valuePart = valuePart.Substring(0, commentIndex).TrimEnd();
}
if (valuePart.Length == 0)
{
builder.AppendLine(key);
continue;
}
builder.AppendLine(key + " " + valuePart);
}
}
return builder.ToString();
}
/// <summary>
/// 读取当前配置文件内容
/// </summary>
/// <returns>返回配置文件内容</returns>
private static string ReadCurrentConfigContent()
{
return CleanConfigContent(System.IO.File.ReadAllText(fileConfig));
}
/// <summary>
/// 获取实时配置文件内容,配置文件修改后自动重新读取
/// </summary>
/// <returns>返回实时配置文件内容</returns>
private static string GetRealTimeConfigContent()
{
DateTime lastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
if (lastWriteTimeUtc == realTimeConfigLastWriteTimeUtc)
{
return realTimeConfigContent;
}
lock (realTimeConfigLock)
{
lastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(fileConfig);
if (lastWriteTimeUtc != realTimeConfigLastWriteTimeUtc)
{
realTimeConfigContent = ReadCurrentConfigContent();
realTimeConfigLastWriteTimeUtc = lastWriteTimeUtc;
}
return realTimeConfigContent;
}
}
/// <summary>
/// 替换某个配置项的值,当行配置,
/// </summary>
/// <param name="configName"></param>
public static void SetItemValue(string configName, string newValue)
{
lock (realTimeConfigLock)
{
try
{
// 读取所有行
var lines = File.ReadAllLines(fileConfig);
// 遍历每一行进行替换
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i].TrimStart(); // 去掉前面空格,方便判断
// 跳过 # 注释行
if (line.StartsWith("#") || string.IsNullOrWhiteSpace(line))
continue;
// 找到 SOCKS5_server 行(不区分大小写、支持前后空格)
if (line.StartsWith(configName, StringComparison.OrdinalIgnoreCase))
{
string pattern = $@"(?m)^({Regex.Escape(configName)}\s+)([^\s#]+)(\s*#.*)?$";
string result = Regex.Replace(
line,
pattern,
m => $"{m.Groups[1].Value}{newValue}{m.Groups[3].Value}"
);
lines[i] = result;
}
}
// 写文件
File.WriteAllLines(fileConfig, lines);
Console.WriteLine($"✅ {configName},替换成功!");
// 重新读取配置文件内容
Init(fileConfig);
}
catch (Exception ex)
{
Console.WriteLine($"❌配置项{configName}替换出错:{ex.Message}");
}
}
}
/// <summary>
/// 读取单行配置文件sysData.ini节点的值
/// </summary>
/// <param name="configName">节点名称</param>
/// <returns>返回节点值</returns>
public static string GetConfigValue(string configName)
{
try
{
//解析配置
Regex regular3 = new Regex($"(?<={configName}).*");
string nodeValue = regular3.Match(configContent).Value;
//获取值移除左右空格
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 实时读取单行配置文件sysData.ini节点的值,配置文件修改后自动重新读取
/// </summary>
/// <param name="configName">节点名称</param>
/// <returns>返回节点值</returns>
public static string? GetConfigValueRealTime(string configName)
{
try
{
string currentConfigContent = GetRealTimeConfigContent();
//解析配置
Regex regular3 = new Regex($"(?<={configName}).*");
string nodeValue = regular3.Match(currentConfigContent).Value;
//获取值移除左右空格
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
//return null;
}
/// <summary>
/// 获取列表配置项
/// </summary>
/// <param name="configName">配置项名称</param>
/// <returns>返回list字符串集合</returns>
public static ReadOnlySpan<string> GetConfigList(string configName)
{
string nodeValue = String.Empty;
try
{
Regex regular5 = new Regex($"(?<=({configName})\\s+\\[)(.*\\n)*(?=])");
string txt = configContent.Substring(configContent.IndexOf(configName));
txt = txt.Substring(0, txt.IndexOf("]") + 1);
nodeValue = regular5.Match(txt).Value;
nodeValue = nodeValue.Trim();
//return nodeValue.Split("\r\n",StringSplitOptions.RemoveEmptyEntries).ToList();
var list = nodeValue.Split(System.Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
return new ReadOnlySpan<string>(list);
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取数组配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 实时获取列表配置项,配置文件修改后自动重新读取
/// </summary>
/// <param name="configName">配置项名称</param>
/// <returns>返回list字符串集合</returns>
public static ReadOnlySpan<string> GetConfigListRealTime(string configName)
{
string nodeValue = String.Empty;
try
{
string currentConfigContent = GetRealTimeConfigContent();
Regex regular5 = new Regex($"(?<=({configName})\\s+\\[)(.*\\n)*(?=])");
string txt = currentConfigContent.Substring(currentConfigContent.IndexOf(configName));
txt = txt.Substring(0, txt.IndexOf("]") + 1);
nodeValue = regular5.Match(txt).Value;
nodeValue = nodeValue.Trim();
//return nodeValue.Split("\r\n",StringSplitOptions.RemoveEmptyEntries).ToList();
var list = nodeValue.Split(System.Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
return new ReadOnlySpan<string>(list);
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取数组配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 读取似xml节点以Long_Text.开头配置里面的多行字符串
/// </summary>
/// <param name="configName">Long_Text.节点名称</param>
/// <returns>返回xml之间配置的值</returns>
public static string GetXml(string configName)
{
//(?<=<Long_Text.wusong>)[\s\S]*(?=</Long_Text.wusong>)
string nodeValue = String.Empty;
try
{
Regex regular5 = new Regex($"(?<=<Long_Text.{configName}>)[\\s\\S]*(?=</Long_Text.{configName}>)");
nodeValue = regular5.Match(configContent).Value;
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
}
/// <summary>
/// 实时读取似xml节点以Long_Text.开头配置里面的多行字符串,配置文件修改后自动重新读取
/// </summary>
/// <param name="configName">Long_Text.节点名称</param>
/// <returns>返回xml之间配置的值</returns>
public static string GetXmlRealTime(string configName)
{
//(?<=<Long_Text.wusong>)[\s\S]*(?=</Long_Text.wusong>)
string nodeValue = String.Empty;
try
{
string currentConfigContent = GetRealTimeConfigContent();
Regex regular5 = new Regex($"(?<=<Long_Text.{configName}>)[\\s\\S]*(?=</Long_Text.{configName}>)");
nodeValue = regular5.Match(currentConfigContent).Value;
return nodeValue.Trim();
}
catch (Exception ex)
{
var ex2 = ex.InnerException ?? ex;
throw new Exception($"读取配置{configName}异常:{ex2.Message}");
}
}
}
}
sysData.ini配置文件内容:
# 说明:#开头的是注释,
#配置项格式要求,参数名+空格+参数值
#行内末尾加注释:参数名+ 空格+参数值 + 空格 + # + 注释内容,不能直接紧贴参数名、参数值写#,#前必须有空白符(空格 /tab)
#Long_Text.参数名: 内部参数不支持行内末尾注释
#列表配置,[]括号内部的内容,行首#表示注释这行;不支持行内末尾注释;
###################测试环境配置文件#####################
#是否需要上传日志到在线服务,1=需要,2=不用;改动后实时生效不用重启程序;
IsUploadLogToOnlineService 2
#color #ffffff #设置控制台#字体颜色
#客户端名称,用于上报到TCP服务端,区分在哪个机器上
ClientName 51646465481
#主程序更新,在线配置文件,新版本下载地址在里面存起
MainUpdateFileOnlineConfigURL http://update.test.com/MainUpdateConfig.json
#业务程序更新,在线配置文件
AppUpdateFileOnlineConfigURL http://update.test.com/AppUpdateConfig.json
#解析域名为TCP服务端ip【开发环境】
TCP_Server_domain master.test.com
#本地TCP服务端,端口号,主控与业务程序通信,9688
tcp_server_port 9688
#业务程序启动,客户端验证包,发送账号密码
Verify_UserName test #账号
Verify_Password test #密码
#在线日志服务,
logbull_host http://ls.test.com
logbull_project_login 81a1e6f0-14c7-4162-b4a1-2371e25c0c3d #项目id
logbull_project_heartBeat 1603063a-307d-4491-a9d8-21cb08035bb2 #项目id
读取配置参考代码:
//在线配置文件地址
string appUpdateConfigUrl = MyConfigReader.GetConfigValue("MainUpdateFileOnlineConfigURL");
另一篇文章,可以查看多一些的配置文件内容格式
https://blog.csdn.net/u011511086/article/details/110928914