10.6.5 ini文件操作

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

ini文件常用作windows的系统配置文件,主要用于早期Windows系统(如win98)保存配置使用。现在虽然程序常用xml文件保存相关配置,但ini文件使用场合还是比较多,还是有必要介绍一下它的读写。

ini文件相对于Xml更简单,它由节(section)、键(Key)、键值(Value)构成。通常情况,节包含在中括号里面,下面是键值对,另外,;(分号)表示注释内容。

以下是一个ini文件内容的示例:

;这里是注释内容

【section】

KeyName=KeyValue

注意:由于ini文件格式比较古老,如果内容中含有中文,使用在记事本中编辑完后,保存的时候请选择编码为ANSI,使用其它编码在程序中将会识别为乱码。

10.6.5.1 读写ini文件使用到的API函数

读取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);

参数说明:

  1. lpApplicationName:ini文件节名称。
  2. lpKeyName:ini文件,lpApplicationName节下的键名称。
  3. lpDefault:如果lpKeyName不存在时,返回的值
  4. lpReturnedString:放置返回值的缓冲区,在使用此函数前,应该先分配缓冲区。
  5. nSize:缓冲区的大小。
  6. lpFileName:ini文件全路径,如果不是全路径,那么程序将使用Windows系统的路径。

返回值:

  1. 如果正确获得了键值,那么返回键值的长度。否则返回0。

2、WritePrivateProfileString声明如下:

        [DllImport("kernel32.dll",  CharSet = CharSet.Unicode)]

        private static extern int WritePrivateProfileString(

            string lpApplicationName,

            string lpKeyName,

            string lpString,

        string lpFileName);

参数说明:

  1. lpApplicationName:ini文件节名称。
  2. lpKeyName:ini文件,lpApplicationName节下的键名称。
  3. lpString:要写入的键值。
  4. lpFileName:ini文件全路径,如果不是全路径,那么程序将使用Windows系统的路径。

返回值:

  1. 如果写入错误返回0,否则返回非0。

【例 10.29【项目:code10-029】ini文件的读写。

本例中使用到的controls.ini文件内容如下:

[control]

appname=串口操作

port=COM1

请在窗体代码中包含GetPrivateProfileStringWritePrivateProfileString函数的定义。

具体代码如下:

        //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.6.5 ini文件操作_第1张图片

图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.6.5 ini文件操作_第2张图片

图10-18 选择不同语言时的程序界面

使用第10.6.1节中文本文件读写的方法也是可以操作ini文件的,但是读写时需要分析键名和键值无疑增加了工作量,使用API的方式更简单。

10.6.5.2 枚举节、键和键值

如果需要获取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.6.5 ini文件操作_第3张图片

图10-19 枚举ini文件中的节名称以及键值对

学习更多vb.net知识,请参看vb.net 教程 目录

学习更多C#知识,请参看C#教程 目录

 

你可能感兴趣的:(C#,教程,c#,ini)