C# 配置文件实战:INI 的读取、修改与删
|
admin
2026年10月17日 14:25
本文热度 36
|
1、配置格式如下:
[Database]Server=127.0.0.1Port=3306Database=TestDB
[Camera]Exposure=100Gain=2.5AutoFocus=1
[System]LogLevel=DebugEnableLog=1
2、函数调用:
初始化:string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SysConfig.ini");IniFileHelper config = new IniFileHelper(configPath);读取:string server = config.ReadString("Database", "Server", "127.0.0.1");int port = config.ReadInt("Database", "Port", 3306);double gain = config.ReadDouble( "Camera", "Gain", 1.0);bool autoFocus = config.ReadBool("Camera", "AutoFocus", true);写入:config.WriteString("Database", "Server", "192.168.0.12");config.WriteInt("Database", "Port", 3307);config.WriteDouble("Camera", "Gain", 2.5);config.WriteBool("Camera", "AutoFocus", false);
3、帮助类
Windows 本身就提供了 INI 文件的读写接口,因此 C# 中不需要自己解析整个文件,可以直接通过 P/Invoke 调用系统提供的GetPrivateProfileString、WritePrivateProfileString 等函数。
public sealed class IniFileHelper{ private const int InitialBufferSize = 256; private const int MaxBufferSize = 1024 * 1024;
private readonly string _filePath; private readonly object _syncRoot = new object();
#region Windows API
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint GetPrivateProfileSectionNames(StringBuilder lpszReturnBuffer, uint nSize, string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint GetPrivateProfileSection(string lpAppName, StringBuilder lpReturnedString, uint nSize, string lpFileName);
#endregion
public IniFileHelper(string filePath) { if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentException("INI 文件路径不能为空。", nameof(filePath));
_filePath = Path.GetFullPath(filePath);
string directory = Path.GetDirectoryName(_filePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } }
/// <summary> /// 当前 INI 文件路径 /// </summary> public string FilePath { get { return _filePath; } }
/// <summary> /// 判断配置文件是否存在 /// </summary> public bool Exists { get { return File.Exists(_filePath); } }
#region String /// <summary> /// 读取字符串配置。 /// </summary> public string ReadString(string section, string key, string defaultValue = "") { if (string.IsNullOrEmpty(section)) throw new ArgumentException("Section 不能为空。", nameof(section));
if (string.IsNullOrEmpty(key)) throw new ArgumentException("Key 不能为空。", nameof(key));
lock (_syncRoot) { StringBuilder buffer = new StringBuilder(InitialBufferSize);
while (true) { uint length = GetPrivateProfileString(section, key, defaultValue, buffer, (uint)buffer.Capacity, _filePath);
// 返回值小于缓冲区大小,说明读取完整 if (length < buffer.Capacity - 1) { return buffer.ToString(); }
// 扩容 if (buffer.Capacity >= MaxBufferSize) { return buffer.ToString(); }
buffer.Capacity = Math.Min(buffer.Capacity * 2, MaxBufferSize); } } }
/// <summary> /// 写入字符串配置。 /// </summary> public void WriteString(string section, string key, string value) { if (string.IsNullOrEmpty(section)) throw new ArgumentException("Section 不能为空。", nameof(section));
if (string.IsNullOrEmpty(key)) throw new ArgumentException("Key 不能为空。", nameof(key));
lock (_syncRoot) { bool result = WritePrivateProfileString(section, key, value ?? string.Empty, _filePath);
if (!result) { throw new IOException("写入 INI 文件失败:" + _filePath); } } } #endregion
#region Int public int ReadInt(string section, string key, int defaultValue = 0) { string value = ReadString(section, key, defaultValue.ToString(CultureInfo.InvariantCulture));
int result;
if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) { return result; }
return defaultValue; }
public void WriteInt(string section, string key, int value) { WriteString(section, key, value.ToString(CultureInfo.InvariantCulture)); } #endregion
#region Double public double ReadDouble(string section, string key, double defaultValue = 0) { string value = ReadString(section, key, defaultValue.ToString(CultureInfo.InvariantCulture));
double result;
if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out result)) { return result; }
return defaultValue; }
public void WriteDouble(string section, string key, double value) { WriteString(section, key, value.ToString(CultureInfo.InvariantCulture)); } #endregion
#region Bool public bool ReadBool(string section, string key, bool defaultValue = false) { string defaultText = defaultValue ? "1" : "0";
string value = ReadString(section, key, defaultText);
if (string.Equals(value, "true", StringComparison.OrdinalIgnoreCase)) { return true; }
if (string.Equals(value, "false", StringComparison.OrdinalIgnoreCase)) { return false; }
int intValue;
if (int.TryParse(value, out intValue)) { return intValue != 0; }
return defaultValue; }
public void WriteBool(string section, string key, bool value) { WriteString(section, key, value ? "1" : "0"); } #endregion
#region Enum public T ReadEnum<T>(string section, string key, T defaultValue) where T : struct { string value = ReadString(section, key, defaultValue.ToString());
T result;
if (Enum.TryParse<T>(value, true, out result)) { return result; }
return defaultValue; }
public void WriteEnum<T>(string section, string key, T value) where T : struct { WriteString(section, key, value.ToString()); } #endregion
#region Generic /// <summary> /// 根据目标类型读取配置。 /// </summary> public T Read<T>(string section, string key, T defaultValue = default(T)) { string value = ReadString(section, key, null);
if (string.IsNullOrWhiteSpace(value)) return defaultValue;
try { Type targetType = typeof(T);
if (targetType == typeof(string)) return (T)(object)value;
if (targetType == typeof(bool)) { bool boolValue;
if (bool.TryParse(value, out boolValue)) return (T)(object)boolValue;
int intValue;
if (int.TryParse(value, out intValue)) return (T)(object)(intValue != 0);
return defaultValue; }
if (targetType.IsEnum) { object enumValue;
try { enumValue = Enum.Parse(typeof(T), value, true);
return (T)enumValue; } catch { return defaultValue; } }
TypeConverter converter = TypeDescriptor.GetConverter(targetType);
if (converter.CanConvertFrom(typeof(string))) { return (T)converter.ConvertFromInvariantString(value); }
return defaultValue; } catch { return defaultValue; } } #endregion
#region Section /// <summary> /// 获取所有 Section。 /// </summary> public List<string> GetSections() { lock (_syncRoot) { int capacity = InitialBufferSize;
while (capacity <= MaxBufferSize) { StringBuilder buffer = new StringBuilder(capacity);
uint length = GetPrivateProfileSectionNames(buffer, (uint)capacity, _filePath);
if (length == 0) return new List<string>();
// 多字符串以 \0 分隔,最后还有一个 \0 if (length < capacity - 2) { return buffer.ToString().Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries).ToList(); }
capacity *= 2; }
return new List<string>(); } } #endregion
#region Key / Value /// <summary> /// 获取指定 Section 下的所有配置项。 /// </summary> public Dictionary<string, string> GetSection(string section) { if (string.IsNullOrEmpty(section)) throw new ArgumentException("Section 不能为空。", nameof(section));
lock (_syncRoot) { int capacity = InitialBufferSize;
while (capacity <= MaxBufferSize) { StringBuilder buffer = new StringBuilder(capacity);
uint length = GetPrivateProfileSection(section, buffer, (uint)capacity, _filePath);
if (length == 0) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (length < capacity - 2) { return ParseSection(buffer.ToString()); }
capacity *= 2; }
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); } }
private Dictionary<string, string> ParseSection(string content) { Dictionary<string, string> result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string[] items = content.Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item in items) { int index = item.IndexOf('=');
if (index < 0) { result[item.Trim()] = string.Empty; continue; }
string key = item.Substring(0, index).Trim();
string value = item.Substring(index + 1);
if (!string.IsNullOrEmpty(key)) { result[key] = value; } }
return result; } #endregion
#region Delete /// <summary> /// 删除指定 Key。 /// </summary> public void DeleteKey(string section, string key) { lock (_syncRoot) { bool result = WritePrivateProfileString(section, key, null, _filePath);
if (!result) { throw new IOException("删除配置项失败:" + section + "/" + key); } } }
/// <summary> /// 删除整个 Section。 /// </summary> public void DeleteSection(string section) { lock (_syncRoot) { bool result = WritePrivateProfileString(section, null, null, _filePath);
if (!result) { throw new IOException("删除 Section 失败:" + section); } } } #endregion
#region Utility /// <summary> /// 判断指定 Key 是否存在。 /// </summary> public bool ContainsKey(string section, string key) { string value = ReadString(section, key, null);
return value != null; }
/// <summary> /// 判断指定 Section 是否存在。 /// </summary> public bool ContainsSection(string section) { return GetSections().Any(x => string.Equals(x, section, StringComparison.OrdinalIgnoreCase)); } #endregion}
该文章在 2026/10/17 14:26:24 编辑过
|
|