.NET 早期版本未內建 INI 檔案操作類別,常見做法是透過 P/Invoke 呼叫 Kernel32.dll 的 WritePrivateProfileString 與 GetPrivateProfileString。本文提供完整封裝類別與使用範例。
using System;
using System.Runtime.InteropServices;
using System.Text;
public static class IniFile
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern long WritePrivateProfileString(
string lpAppName, string lpKeyName, string lpString, string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetPrivateProfileString(
string lpAppName, string lpKeyName, string lpDefault,
StringBuilder lpReturnedString, int nSize, string lpFileName);
// 公開靜態方法
public static void WriteValue(string filePath, string section, string key, string value)
{
WritePrivateProfileString(section, key, value, filePath);
}
public static string ReadValue(string filePath, string section, string key, string defaultValue = "")
{
var sb = new StringBuilder(255);
GetPrivateProfileString(section, key, defaultValue, sb, sb.Capacity, filePath);
return sb.ToString();
}
}
string exePath = System.Windows.Forms.Application.ExecutablePath;
string iniPath = System.IO.Path.ChangeExtension(exePath, ".ini"); // 同目錄同名 .ini
// 寫入
IniFile.WriteValue(iniPath, "Database", "Server", "localhost");
IniFile.WriteValue(iniPath, "Database", "Port", "1433");
IniFile.WriteValue(iniPath, "Database", "User", "sa");
IniFile.WriteValue(iniPath, "Settings", "AutoBackup", "true");
// 讀取
string server = IniFile.ReadValue(iniPath, "Database", "Server");
string port = IniFile.ReadValue(iniPath, "Database", "Port");
bool autoBak = bool.Parse(IniFile.ReadValue(iniPath, "Settings", "AutoBackup", "false"));
Console.WriteLine($"Server={server}, Port={port}, AutoBackup={autoBak}");
[Database]
Server=localhost
Port=1433
User=sa
[Settings]
AutoBackup=true
public class IniFile
{
private readonly string _path;
public IniFile(string path) => _path = path;
public void Write(string section, string key, string value)
=> WritePrivateProfileString(section, key, value, _path);
public string Read(string section, string key, string defaultValue = "")
{
var sb = new StringBuilder(255);
GetPrivateProfileString(section, key, defaultValue, sb, sb.Capacity, _path);
return sb.ToString();
}
public T Read<T>(string section, string key, T defaultValue = default)
{
string val = Read(section, key, null);
if (val == null) return defaultValue;
return (T)Convert.ChangeType(val, typeof(T));
}
// 列舉所有區段 (需呼叫 GetPrivateProfileSectionNames)
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, int nSize, string lpFileName);
public string[] GetSections()
{
int maxSize = 1024;
while (true)
{
var buffer = Marshal.AllocHGlobal(maxSize);
int size = GetPrivateProfileSectionNames(buffer, maxSize, _path);
if (size == 0) { Marshal.FreeHGlobal(buffer); return Array.Empty<string>(); }
if (size < maxSize - 2)
{
string all = Marshal.PtrToStringAuto(buffer, size);
Marshal.FreeHGlobal(buffer);
return all.Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
}
Marshal.FreeHGlobal(buffer);
maxSize *= 2;
}
}
}
若不想依賴 P/Invoke,可使用 NuGet 套件 IniParser:
var parser = new FileIniDataParser();
IniData data = parser.ReadFile("config.ini");
string val = data["Database"]["Server"];
data["Settings"]["Theme"] = "Dark";
parser.WriteFile("config.ini", data);
CharSet = CharSet.Auto 可自動依平台選擇 ANSI/Unicode 版 API。