C# 默认不支持 IniFile 读写,因 .NET 原生配置体系面向 XML/JSON/环境变量,而 Windows API 的 INI 函数跨平台不可用且易出错;推荐手写解析器,用 Dictionary 逐行处理节、键值、编码与注释。
为什么 C# 默认不支持 IniFile 读写
因为 .net 原生配置体系(configurationmanager、iconfiguration)面向的是 xml(app.config)、json(appsettings.json)或环境变量,不是 ini。windows api 虽有 getprivateprofilestring 等函数,但跨平台(.net core / .net 5+)时不可用,且 p/invoke 容易出内存或编码问题。
所以实际项目里,要么自己解析 INI 文本,要么用轻量库——推荐直接手写一个简易解析器,比引入第三方更可控。
- INI 文件本质是键值对 + 节(section),无嵌套、无类型,换行和空格敏感
- Windows 下默认 ANSI 编码(非 UTF-8),读取时若用
Encoding.UTF8会乱码;Linux/macOS 下通常为 UTF-8 -
File.ReadAllText直接读可能丢节头(如[Database]被当注释),需按行解析并识别[xxx]模式
用 Dictionary> 手动解析最稳
不依赖外部包,兼容所有 .NET 版本,且能精准控制编码、空行、注释(; 或 # 开头)处理逻辑。
核心逻辑:逐行读 → 跳过空行和注释 → 遇到 [SectionName] 记录当前节 → 否则按 key=value 拆分(注意等号可能在 value 中,只取第一个)
- 用
File.ReadLines(path)而非ReadAllLines,节省内存,尤其大文件 - value 值要去首尾空白,但保留中间空格;key 同理,且不区分大小写时建议统一转小写存
- 写入时用
StringBuilder拼接,避免多次字符串连接;节名和 key 若含[、=、;等字符,应拒绝写入(INI 规范不支持转义)
var config = new Dictionary<string dictionary string>>();
string currentSection = null;
foreach (var line in File.ReadLines("app.ini", Encoding.Default)) {
var trimmed = line.Trim();
if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith(";") || trimmed.StartsWith("#")) continue;
if (trimmed.StartsWith("[") && trimmed.EndsWith("]")) {
currentSection = trimmed.Substring(1, trimmed.Length - 2).Trim();
config[currentSection] = new Dictionary<string string>(StringComparer.OrdinalIgnoreCase);
continue;
}
int eqPos = trimmed.IndexOf('=');
if (eqPos > 0) {
var key = trimmed.Substring(0, eqPos).Trim();
var value = trimmed.Substring(eqPos + 1).Trim();
config[currentSection][key] = value;
}
}</string></string>
WritePrivateProfileString 在 Windows 上能用,但别在跨平台项目里碰
这是 Win32 API,.NET 可通过 DllImport 调用,但仅限 Windows Desktop(.NET Framework)或启用 WindowsBase 的 .NET Core/6+,且必须指定 CharSet = CharSet.Auto 否则中文写入失败。
- 写入后系统缓存可能导致立即读不到最新值,需调用
FlushFileBuffers或重启应用验证 - 路径含 Unicode 字符时,
lpFileName必须传绝对路径,相对路径可能解析错盘符 - .NET 5+ 默认禁用不安全代码,启用需在 csproj 加
true - macOS/Linux 下直接报
DllNotFoundException,无法 fallback
读写时最容易被忽略的三个点
不是语法错,而是语义和边界没控住:
- INI 没“布尔”或“数字”类型,
enabled=true和timeout=30全是字符串,业务层要用bool.TryParse或int.TryParse转,别信配置值本身 - 节名和 key 允许重复,后出现的会覆盖前一个(如两个
[Log],后者生效),但多数解析器不报错,得靠人工校验 - 写入新 key 时,若目标节不存在,要先创建节(即插入
[NewSection]行),否则该 key 会被写到文件末尾、脱离上下文
复杂点在于:INI 是纯文本协议,没有 schema 校验,也没有原子写入机制——写一半崩溃,文件就损坏。真要可靠,得加临时文件 + 原子重命名,或者干脆换 appsettings.json。










