版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
ini文件常用作windows的系统配置文件,主要用于早期Windows系统(如win98)保存配置使用。现在虽然程序常用xml文件保存相关配置,但ini文件使用场合还是比较多,还是有必要介绍一下它的读写。
ini文件相对于Xml更简单,它由节(section)、键(Key)、键值(Value)构成。通常情况,节包含在中括号里面,下面是键值对,另外,;(分号)表示注释内容。
以下是一个ini文件内容的示例:
;这里是注释内容
【section】
KeyName=KeyValue
注意:由于ini文件格式比较古老,如果内容中含有中文,使用在记事本中编辑完后,保存的时候请选择编码为ANSI,使用其它编码在程序中将会识别为乱码。
读取ini文件使用到API,需要在所有代码前加上:
using System.Runtime.InteropServices;
读取ini文件键值的API:GetPrivateProfileString。
写入ini文件键值的API:WritePrivateProfileString。
1、GetPrivateProfileString声明如下:
[DllImport("kernel32.dll", CharSet =CharSet.Unicode )]
private static extern int GetPrivateProfileString(
string lpApplicationName,
string lpKeyName,
string lpDefault,
StringBuilder lpReturnedString,
int nSize,
string lpFileName);
参数说明:
返回值:
2、WritePrivateProfileString声明如下:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern int WritePrivateProfileString(
string lpApplicationName,
string lpKeyName,
string lpString,
string lpFileName);
参数说明:
返回值:
【例 10.29】【项目:code10-029】ini文件的读写。
本例中使用到的controls.ini文件内容如下:
[control]
appname=串口操作
port=COM1
请在窗体代码中包含GetPrivateProfileString和WritePrivateProfileString函数的定义。
具体代码如下:
//ini文件路径
string filename = "c:\\lessons\\controls.ini";
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i <= 10; i++)
comboBox1.Items.Add("COM" + i);
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
}
private void button1_Click(object sender, EventArgs e)
{
//GetPrivateProfileString的返回值
int Rvalue;
//缓冲区大小
int BufferSize = 255;
//缓冲区
StringBuilder keyValue = new StringBuilder(BufferSize);
//段名称
string sectionName = "control";
//键名称
string keyName = "appname";
string result="";
//将项名称、键名称、默认值、缓冲区、缓冲区大小、ini文件传递给GetPrivateProfileString
Rvalue = GetPrivateProfileString(sectionName, keyName, "", keyValue, BufferSize, filename);
//如果返回值为0,不成功
if (Rvalue == 0)
result = "(没有获得相应的值)";
else
result = keyValue.ToString();
textBox1.Text = result;
keyName = "port";
keyValue = new StringBuilder(BufferSize);
Rvalue = GetPrivateProfileString(sectionName, keyName, "", keyValue, BufferSize, filename);
if (Rvalue == 0)
result = "(没有获得相应的值)";
else
result = keyValue.ToString();
comboBox1.Text = result;
}
private void button2_Click(object sender, EventArgs e)
{
//段名称
string sectionName= "control";
//键名称
string keyName = "appname";
string keyValue;
keyValue = textBox1.Text;
//WritePrivateProfileString的返回值
int Rvalue;
//将项名称、键名称、键值、ini文件传递给WritePrivateProfileString
Rvalue = WritePrivateProfileString(sectionName, keyName, keyValue, filename);
//返回0,产生错误
if (Rvalue == 0)
{
int errCode = Marshal.GetLastWin32Error();
MessageBox.Show("发生错误,错误代码 " + errCode.ToString());
}
keyName = "port";
keyValue = comboBox1.Text;
Rvalue = WritePrivateProfileString(sectionName, keyName, keyValue, filename);
if (Rvalue == 0)
{
int errCode = Marshal.GetLastWin32Error();
MessageBox.Show("发生错误,错误代码 " + errCode.ToString());
}
}
运行结果如下图所示:
图10-17 读写ini文件
【例 10.30】【项目:code10-030】中英文显示界面切换。
本例中,用户可以通过选择中文或英文,从而实现界面根据用户需要显示不同的语言。
需要的两个ini文件:
language_ch.ini:存放中文内容。具体内容如下:
[gui]
appname=这是我的程序
language=选择语言
Save=保存
Open=打开
Exit=退出
language_en.ini:存放英文内容。具体内容如下:
[gui]
appname=This is my App
language=Choose Language
Save=Save
Open=Open
Exit=Exit
两个ini文件相比较,节名称相同,键名称相同,键值不同。
请在窗体代码中包含GetPrivateProfileString函数的定义。
具体代码如下:
//定义中文语言配置文件路径
string chFileName = "c:\\lessons\\language_ch.ini";
//定义英文语言配置文件路径
string enFileName = "c:\\lessons\\language_en.ini";
//窗体载入时候,选择中文语言
private void Form1_Load(object sender, EventArgs e)
{
rbCh.Checked = true;
}
//当选择不同的单选框时,切换语言
private void rbCh_CheckedChanged(object sender, EventArgs e)
{
if (rbCh.Checked == true)
getGuiLanguage(chFileName);
else
getGuiLanguage(enFileName);
}
//调用getKeyValue读取相应的键值对
private void getGuiLanguage(string filename)
{
lblAppname.Text = getKeyValue("gui", "appname", filename);
gbLanguage.Text = getKeyValue("gui", "language", filename);
btnSave.Text = getKeyValue("gui", "Save", filename);
btnOpen.Text = getKeyValue("gui", "Open", filename);
btnExit.Text = getKeyValue("gui", "Exit", filename);
}
//读取ini文件中相应的键值对
private string getKeyValue(string sectionName , string keyName , string filename)
{
int Rvalue;
string result="";
int BufferSize = 255;
StringBuilder keyValue = new StringBuilder(BufferSize);
Rvalue = GetPrivateProfileString(sectionName, keyName, "", keyValue, BufferSize, filename);
if(Rvalue == 0)
result = "(没有获得相应的值)";
else
result = keyValue.ToString();
return result;
}
运行结果如下图所示:
图10-18 选择不同语言时的程序界面
使用第10.6.1节中文本文件读写的方法也是可以操作ini文件的,但是读写时需要分析键名和键值无疑增加了工作量,使用API的方式更简单。
如果需要获取ini文件中所有的 section和 Key,仍然可以使用GetPrivateProfileString函数。这个重载版本的声明中,参数lpReturnedString与10.6.5.1节【读写ini文件使用到的API函数】里面的有所不同:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern int GetPrivateProfileString(
string lpApplicationName,
string lpKeyName,
string lpDefault,
string lpReturnedString,
int nSize,
string lpFileName);
参数 lpApplicationName 指定了ini文件节名称,参数 lpKeyName 指定了lpApplicationName节下的键名称,当这两个参数都设置为 null的时候,就可以通过传入的参数 lpReturnedString 返回一个包含所有节(section)的字符串,其中每个 section 之间用 ‘\0’隔开,字符串末尾是两个‘\0’。
同样,当指定了 lpApplicationName 为某节名称的字符串,lpApplicationName 设置为 null的时候,通过传入的参数 lpReturnedString 返回一个包含所有键(Key)的字符串,其中每个 Key 之间用‘\0’ 隔开,字符串末尾是两个‘\0’。
使用以上方法就可以获得所有的节和键名。
【例 10.31】【项目:code10-031】枚举ini文件的键值对。
使用到的范例appconfig.ini文件内容如下:
[control]
appname=ini文件读写
[setting]
language=中文
port=COM4
[times]
writetime=2019-10-01
readtime=2019-10-10
具体代码如下:
string filename = "c:\\lessons\\appconfig.ini";
// 使用GetPrivateProfileString获取所有节名称
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
//以下代码使用 StringBuilder,只能返回第一个节的名称
//string[] sectionarr;
//int Rvalue;
//int BufferSize = 1024;
//StringBuilder sectionnames = new StringBuilder(BufferSize);
将参数lpApplicationName和参数lpKeyName设置为空字符串传递给GetPrivateProfileString
//Rvalue = GetPrivateProfileString(null, null, null, sectionnames, BufferSize, filename);
//if( Rvalue == 0)
//{
// MessageBox.Show("发生错误 " + Marshal.GetLastWin32Error());
// return;
//}
将字符串拆分为数组
//sectionarr = sectionnames.ToString().Split('\0');
//foreach (string section in sectionarr)
// listBox1.Items.Add(section);
string[] sectionarr;
int Rvalue;
int BufferSize = 1024;
string sectionnames = new string('\0',BufferSize);
//将参数lpApplicationName和参数lpKeyName设置为null传递给GetPrivateProfileString
Rvalue = GetPrivateProfileString(null, null, "", sectionnames, BufferSize, filename);
if (Rvalue == 0)
{
MessageBox.Show("发生错误 " + Marshal.GetLastWin32Error());
return;
}
//将字符串拆分为数组
sectionarr = sectionnames.ToString().Split(new char[] { '\0' },StringSplitOptions.RemoveEmptyEntries);
foreach (string section in sectionarr)
listBox1.Items.Add(section);
}
//在ListBox2中列出所选节名称下的键值对
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex < 0)
return;
listBox2.Items.Clear();
string sectionName = listBox1.Items[listBox1.SelectedIndex].ToString();
string result;
string[] keyarr;
int Rvalue;
int BufferSize = 255;
string keys = new string('\0',BufferSize);
//将参数lpApplicationName设置具体名称,将参数lpKeyName设置为null传递给GetPrivateProfileString
Rvalue = GetPrivateProfileString(sectionName, null, "", keys, BufferSize, filename);
if (Rvalue == 0)
{
MessageBox.Show("发生错误 " + Marshal.GetLastWin32Error());
return;
}
//去掉键名字符串末尾的2个vbNullChar
result = keys.ToString();
keyarr = result.Split(new char[] { '\0' },StringSplitOptions.RemoveEmptyEntries);
foreach (string keyname in keyarr)
{
StringBuilder keyValue = new StringBuilder(BufferSize);
string keyResult="";
int Rvalue1;
Rvalue1 = GetPrivateProfileString(sectionName, keyname, "", keyValue, BufferSize, filename);
if (Rvalue == 0)
{
MessageBox.Show("发生错误 " + Marshal.GetLastWin32Error());
}
else
{
keyResult = keyValue.ToString();
listBox2.Items.Add(keyname + "=" + keyResult);
}
}
}
获取ini文件中所有section名称的另一个API函数GetPrivateProfileSectionNames,其声明如下:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern int GetPrivateProfileSectionNames(
string lpszReturnBuffer,
int nSize,
string lpFileName);
使用代码如下:
//使用GetPrivateProfileSectionNames获取所有节名称
private void button2_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
string[] sectionarr;
int Rvalue;
int BufferSize = 1024;
string sectionnames = new string('\0', 1024);
Rvalue = GetPrivateProfileSectionNames(sectionnames, BufferSize, filename);
if (Rvalue == 0)
{
MessageBox.Show("发生错误 " + Marshal.GetLastWin32Error());
return;
}
sectionarr = sectionnames.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string section in sectionarr)
listBox1.Items.Add(section);
}
button2_Click和button1_Click实现的效果相同。
运行结果如下图所示:
图10-19 枚举ini文件中的节名称以及键值对
学习更多vb.net知识,请参看vb.net 教程 目录
学习更多C#知识,请参看C#教程 目录