C#读写ini文件
调用winAPI 实现ini文件操作
- dll路径:C:\Windows\System32\kernel32.dll;
- 若调用失败可查看dll是否存在以及环境变量(C:\Windows\System32)是否已设置
- 静态类编写如下
文件采用默认路径,若需要改变,调用之前请先更新文件路径
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace BasicExercises
{
/***
* ini文件样式
* [配置项]
* 属性1 = 属性值
* 属性2 = 属性值
* ...
*
* CharSet定义的时候使用了什么类型,在使用相关方法时必须要使用相应的类型
* 例如 GetPrivateProfileSectionNames声明为CharSet.Auto,那么就应该使用 Marshal.PtrToStringAuto来读取相关内容
* 如果使用的是CharSet.Ansi,就应该使用Marshal.PtrToStringAnsi来读取内容
* **/
class IniConfigHelper
{
static string iniFilePath = Environment.CurrentDirectory+"config.ini";
public static string IniFilePath { get => iniFilePath; set => iniFilePath = value; }
/***
* 调用winAPI 实现ini文件操作
* dll路径:C:\Windows\System32\kernel32.dll,若调用失败可查看dll是否存在以及环境变量(C:\Windows\System32)是否已设置
* 以下是API函数
***/
/// <summary>
/// 写入ini文件:将指定的键和值写到指定的节点,如果已经存在则替换
/// </summary>
/// <param name="section">节点名称</param>
/// <param name="key">键,null也直接写入</param>
/// <param name="value">值,null也直接写入</param>
/// <param name="filePath">ini文件路径</param>
/// <returns>0失败/其他成功</returns>
//[DllImport("kernel32", CharSet = CharSet.Auto)]
//private static extern long WritePrivateProfileString(string section, string key, string value, string filePath);
/// <summary>
/// 写入ini文件:将指定的键和值写到指定的节点,如果已经存在则替换
/// </summary>
/// <param name="section">节点名称</param>
/// <param name="key">键,null则删除指定的节点及其所有的项目</param>
/// <param name="value">值,null则删除指定节点中指定的键</param>
/// <param name="filePath">ini文件路径</param>
/// <returns>操作是否成功</returns>
[DllImport("kernel32", CharSet = CharSet.Auto)]
private static extern bool WritePrivateProfileString(string section, string key, string value, string filePath);
/// <summary>
/// 将指定的键值对写到指定的节点,如果已经存在则替换。
/// </summary>
/// <param name="section">节点,如果不存在此节点,则创建此节点</param>
/// <param name="keyValue">Item键值对,多个用\0分隔,形如key1=value1\0key2=value2
/// 如果为string.Empty,则删除指定节点下的所有内容,保留节点
/// 如果为null,则删除指定节点下的所有内容,并且删除该节点
/// 该方法无脑写入,遇"\0"换行写入
/// </param>
/// <param name="filePath"></param>
/// <returns>操作成功与否</returns>
[DllImport("kernel32", CharSet = CharSet.Auto)]
private static extern bool WritePrivateProfileSection(string section, string keyValue, string filePath);
/// <summary>
/// 调用winAPI读取ini文件
/// </summary>
/// <param name="section">节点名称</param>
/// <param name="key">键</param>
/// <param name="def">值(未读取到数据时设置的默认返回值)</param>
/// <param name="result">读取的结构值</param>
/// <param name="size">读取的缓冲区大小</param>
/// <param name="filePath">ini路径</param>
/// <returns>读取到的字节数量</returns>
[DllImport("kernel32", CharSet = CharSet.Auto)]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder result, int size, string filePath);
/// <summary>
/// 获取所有节点名称(Section)
/// </summary>
/// <param name="ptrResultBuffer">存放节点名称的内存地址,每个节点之间使用\0分隔</param>
/// <param name="nSize">内存大小</param>
/// <param name="filePath">ini文件路径</param>
/// <returns>内容的实际长度,为0表示没有内容,为nSize-2表示内存大小不够</returns>
[DllImport("kernel32", CharSet = CharSet.Auto)]
private static extern uint GetPrivateProfileSectionsNames(IntPtr lpResultBuffer,uint nSize,string filePath);
/// <summary>
/// 获取某个指定节点(Section)中所有KEY和Value
/// </summary>
/// <param name="section">节点名称</param>
/// <param name="lpReturnedString">返回值的内存地址,每个之间使用\0分隔</param>
/// <param name="nSize">内存大小</param>
/// <param name="filePath">ini文件地址</param>
/// <returns></returns>
[DllImport("kernel32", CharSet = CharSet.Auto)]
private static extern uint GetPrivateProfileSection(string section, IntPtr lpReturnedString, uint nSize, string filePath);
/***
* 调用winAPI 实现ini文件操作
* 以下是API对应的调用函数封装
***/
/// <summary>
/// 写入ini,指定节点下单键值对写入
/// </summary>
/// <param name="section"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns>操作成功与否</returns>
public static bool WriteToIni(string section, string key, string value)
{
if (string.IsNullOrEmpty(section))
{
return false;
//throw new ArgumentException("必须指定节点名称",section);
}
if (string.IsNullOrEmpty(key))
{
return false;
//throw new ArgumentException("必须指定key值",key);
}
if (string.IsNullOrEmpty(value))
{
return false;
//throw new ArgumentException("值不能为空",value);
}
return WritePrivateProfileString(section, key, value, iniFilePath);
}
/// <summary>
/// 删除指定节点下指定键
/// </summary>
/// <param name="section">节点</param>
/// <param name="key">键</param>
/// <returns>操作成功与否</returns>
public static bool DeleteKey(string section, string key)
{
if (string.IsNullOrEmpty(section))
{
return false;
//throw new ArgumentException("必须指定节点名称",section);
}
if (string.IsNullOrEmpty(key))
{
return false;
//throw new ArgumentException("必须指定key值",key);
}
return WritePrivateProfileString(section, key, null, iniFilePath);
}
/// <summary>
/// 删除指定节点
/// </summary>
/// <param name="section">节点</param>
/// <returns>操作成功与否</returns>
public static bool DeleteSection(string section)
{
if (string.IsNullOrEmpty(section))
{
return false;
//throw new ArgumentException("必须指定节点名称",section);
}
return WritePrivateProfileString(section, null, null, iniFilePath);
}
/// <summary>
/// 清空指定节点
/// </summary>
/// <param name="section">节点</param>
/// <returns>操作成功与否</returns>
public static bool EmptySection(string section)
{
if (string.IsNullOrEmpty(section))
{
return false;
//throw new ArgumentException("必须指定节点名称",section);
}
return WritePrivateProfileSection(section,string.Empty,iniFilePath);
}
/// <summary>
/// 写入ini,指定节点下多个键值对写入
/// </summary>
/// <param name="section">节点</param>
/// <param name="keyValue">键值对,形如key1=value1\0key2=value2 </param>
/// <returns></returns>
public static bool WriteToIniSection(string section, string keyValue)
{
if (string.IsNullOrEmpty(section))
{
return false;
//throw new ArgumentException("必须指定节点名称",section);
}
if (string.IsNullOrEmpty(keyValue))
{
return false;
//throw new ArgumentException("键值对不能为空",keyValue);
}
return WritePrivateProfileSection(section, keyValue, iniFilePath);
}
/// <summary>
/// 读取ini,section和key不能为null
/// </summary>
/// <param name="section">节点</param>
/// <param name="key">键</param>
/// <returns>null或读取结果</returns>
public static string ReadFromIni(string section,string key)
{
if (string.IsNullOrEmpty(section))
{
return null;
//throw new ArgumentException("必须指定节点名称", section);
}
if (string.IsNullOrEmpty(key))
{
return null;
//throw new ArgumentException("必须指定key值", key);
}
int size = 1024;
StringBuilder builder = new StringBuilder(size);
//string def = "";
int result = GetPrivateProfileString(section, key, "", builder, size, iniFilePath);
return builder.ToString();
}
/// <summary>
/// 获取ini文件所有节点
/// </summary>
/// <returns>所有节点,没有内容返回string[0]</returns>
public static string[] GetAllSections()
{
uint MAX_BUFFER = 32767;
string[] sections = new string[0];
//申请内存
IntPtr pReturnedStr = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char));
//读取内容
uint nSize = GetPrivateProfileSectionsNames(pReturnedStr, MAX_BUFFER, iniFilePath);
if (nSize != 0 && nSize != MAX_BUFFER - 2)
{
//读取内存内存
string returnedStr = Marshal.PtrToStringAuto(pReturnedStr, (int)nSize);
//转换成string[]格式
sections = returnedStr.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
}
//释放内存
Marshal.FreeCoTaskMem(pReturnedStr);
return sections;
}
/// <summary>
/// 获取指定节点下的所有key、value;形式key=value
/// </summary>
/// <param name="section">指定节点</param>
/// <returns>指定节点的所有条目,空则返回string[0]</returns>
public static string[] GetAllKeyValueBySection(string section)
{
if (string.IsNullOrEmpty(section))
{
return null;
//throw new ArgumentException("必须指定节点名称", section);
}
uint MAX_BUFFER = 32767;
string[] items = new string[0];
//分配内存
IntPtr pReturnedStr = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char));
uint nSize = GetPrivateProfileSection(section, pReturnedStr, MAX_BUFFER, iniFilePath);
if (nSize != 0 && nSize != MAX_BUFFER - 2)
{
//读取内存内容
string returnedStr = Marshal.PtrToStringAuto(pReturnedStr, (int)nSize);
每个节点之间用\0分隔,末尾有一个\0
items = returnedStr.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
}
//释放内存
Marshal.FreeCoTaskMem(pReturnedStr);
return items;
}
}
}
- 调用窗口:
csharp
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BasicExercises
{
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
}
private void btnTestIni_Click(object sender, EventArgs e)
{
string userSection = "用户";
string userNameKey = "Name";
string testSection = "测试节点";
string keyValue = "用户1=苏\0密码=苏\0用户2=林\0密码=林";
//ini写入
txtBoxMsg.Text = "";
txtBoxMsg.Text += "测试写入以下内容:\r\n[" + userSection + "]\r\n" + userNameKey + " = 测试用户";
bool IsWriteSec = IniConfigHelper.WriteToIni(userSection, userNameKey, "测试用户");
if (IsWriteSec)
{
txtBoxMsg.Text += "\r\n写入成功!";
}
//多个键值对写入
// \0 在C#中代表结束字符,不会被窗体输出
txtBoxMsg.Text += "\r\n" + keyValue;
IsWriteSec = IniConfigHelper.WriteToIniSection(testSection, keyValue);
if (IsWriteSec)
{
txtBoxMsg.Text += "\r\n写入成功!";
}
//ini读取指定键
string value = IniConfigHelper.ReadFromIni(userSection, userNameKey);
txtBoxMsg.Text += "\r\n读取结果:" + value;
//获取ini所有节点
string[] sectionItems = IniConfigHelper.GetAllKeyValueBySection(testSection);
string allSection = "";
foreach (string item in sectionItems)
{
allSection += item;
}
txtBoxMsg.Text += "\r\n获取ini所有节点:" + allSection;
//获取ini指定节点下的所有key和value
string[] items = IniConfigHelper.GetAllKeyValueBySection(testSection);
string msg = "";
foreach (string item in items)
{
msg += item;
}
txtBoxMsg.Text += "\r\n获取ini指定节点下的所有key和value:" + msg;
//删除指定key
IsWriteSec = IniConfigHelper.DeleteKey(userSection, userNameKey);
if (IsWriteSec)
{
txtBoxMsg.Text += "\r\n删除" + "[" + userSection + "]下的键:" + userNameKey + "成功";
}
//删除指定节点
IsWriteSec = IniConfigHelper.DeleteSection(userSection);
if (IsWriteSec)
{
txtBoxMsg.Text += "\r\n删除" + "[" + userSection + "]节点成功";
}
IsWriteSec = IniConfigHelper.DeleteSection(testSection);
if (IsWriteSec)
{
txtBoxMsg.Text += "\r\n删除" + "[" + testSection + "]节点成功";
}
}
}
}

- 运行结果: