# 编程实现对ini配置文件的读写
# 背景
在安装一些应用程序的时候,我们经常可以其安装目录下看到有 .ini 格式的配置文件,这种格式配置文件是我们比较常见的。在我们自己电脑的系统上也会有,而且还很多。很多系统自带的程序,都会有一个 .ini 格式的配置文件。
为此,Windows还特地提供了相应的WIN32 API函数去对 .ini 格式的配置文件进行读写操作。所以,本文就主要介绍下如何使用API函数来实现对 .ini 配置文件的读写。现在,我就把实现过程整理成文档,分享给大家。
# 函数介绍
## WritePrivateProfileString 函数
> 将一个字符串复制到INI文件的指定的字段中。
>
> 函数声明
>
> ```c++
> BOOL WINAPI WritePrivateProfileString(
> _In_ LPCTSTR lpAppName,
> _In_ LPCTSTR lpKeyName,
> _In_ LPCTSTR lpString,
> _In_ LPCTSTR lpFileName
> );
> ```
>
> 参数
>
> - lpAppName [in]
> 要复制字符串的字段名称。 如果该字段不存在,则创建它。
>
> - lpKeyName [in]
>
> 与字符串关联的键的名称。 如果该键在指定的字段下不存在,则创建它。 如果此参数为NULL,则整个字段(包括该字段中的所有的键)将被删除。
>
> - lpString [in]
> 要写入文件的以NULL结尾的字符串。 如果此参数为NULL,则lpKeyName参数指向的键将被删除。
>
> - lpFileName [in]
> INI文件的名称。如果文件是使用Unicode字符创建的,则该函数将Unicode字符写入该文件。 否则,函数写入ANSI字符。
>
> 返回值
>
> - 如果函数成功将字符串复制到初始化文件,则返回值不为零。
> - 如果函数失败,或者刷新最近访问的初始化文件的缓存版本,返回值为零。 要获取扩展错误信息,请调用GetLastError。
## GetPrivateProfileString 函数
> 从INI文件中的指定的字段中获取一个字符串。
>
> 函数声明
>
> ```c++
> DWORD WINAPI GetPrivateProfileString(
> _In_ LPCTSTR lpAppName,
> _In_ LPCTSTR lpKeyName,
> _In_ LPCTSTR lpDefault,
> _Out_ LPTSTR lpReturnedString,
> _In_ DWORD nSize,
> _In_ LPCTSTR lpFileName
> );
> ```
>
> 参数
>
> - lpAppName [in]
> 字段的名称。如果此参数为NULL,则GetPrivateProfileString函数将文件中的所有字段名复制到提供的缓冲区里。
> - lpKeyName [in]
> 要检索的键名。如果此参数为NULL,则由lpAppName参数指定的字段中的所有键名将复制到由lpReturnedString参数指定的缓冲区中。
> - lpDefault [in]
> 默认字符串。如果在INI文件中找不到lpKeyName键,则GetPrivateProfileString将默认字符串复制到lpReturnedString缓冲区。如果此参数为NULL,则默认值为空字符串“”。避免指定一个带有空白字符的默认字符串。该函数在lpReturnedString缓冲区中插入一个空字符以去除任何尾随的空白。
> - lpReturnedString [out]
> 指向接收检索字符串的缓冲区的指针。
> - nSize [in]
> lpReturnedString参数指向的缓冲区的大小,以字符为单位。
> - lpFileName [in]
> INI文件的名称。如果此参数不包含文件的完整路径,系统将在Windows目录中搜索该文件。
>
> 返回值
>
> 返回复制到缓冲区的字符数,不包括终止空字符。
## GetPrivateProfileInt 函数
> 在INI文件中的指定的字段中获取它的整数值。
>
> 函数声明
>
> ```c++
> UINT WINAPI GetPrivateProfileInt(
> _In_ LPCTSTR lpAppName,
> _In_ LPCTSTR lpKeyName,
> _In_ INT nDefault,
> _In_ LPCTSTR lpFileName
> );
> ```
>
> 参数
>
> - lpAppName [in]
> INI文件中的字段名称。
> - lpKeyName [in]
> 要检索其值的键名。此值为字符串的形式,GetPrivateProfileInt函数将字符串转换为整数并返回整数。
> - nDefault [in]
> 如果在初始化文件中找不到键名,返回的默认值。
> - lpFileName [in]
> INI文件的名称。 如果此参数不包含文件的完整路径,系统将在Windows目录中搜索该文件。
>
> 返回值
>
> - 返回INI文件中指定键名后的字符串转换后的整数。
> - 如果找不到键,则返回值是指定的默认值。
# 实现过程
根据上面的函数介绍,我们直接调用上述函数对INI配置文件进行操作。本文的例子如下:
首先,我们调用 WritePrivateProfileString 函数创建一个名为Config.ini的INI文件,并添加INFORMATION和OTHER字段;在INFORMATION字段下,有两个键名分别为name和age的键,其中键名为name中存储的键值是DemonGan,键名为age中存储的键值为18。在OTHER字段中,键名为class的键值为no1。
```c++
char szFileName[] = "C:\\Users\\DemonGan\\Desktop\\ReadWriteIniFile_Test\\Debug\\Config.ini";
// 向INI文件中写入数据
::WritePrivateProfileString("INFORMATION", "name", "DemonGan", szFileName);
::WritePrivateProfileString("INFORMATION", "age", "18", szFileName);
::WritePrivateProfileString("OTHER", "class", "no1", szFileName);
```
那么,生成的INI文件的数据内容如下所示:
![](http://www.writebug.com/myres/static/uploads/2021/10/19/23b4be5e52c5c5271aa6ae58106d5be9.writebug)
然后,我们调用 GetPrivateProfileString 函数,读取INI文件中的INFORMATION字段下的name键的数据。
```c++
// 从INI文件中读取字符串数据
char szReturnString[MAX_PATH] = {0};
::GetPrivateProfileString("INFORMATION", "name", NULL, szReturnString, MAX_PATH, szFileName);
printf("name=%s\n", szReturnString);
```
接着,我们调用 GetPrivateProfileInt 函数,读取INI文件中的INFORMATION字段下的age键的数据。
```c++
// 从INI文件中读取整型数据
int iReturnInt = ::GetPrivateProfileInt("INFORMATION", "age", 0, szFileName);
printf("age=%d\n", iReturnInt);
```
对于类似age=18的整型数据的读取,我们除了可以使用 GetPrivateProfileInt 函数读取之外,还可以使用 GetPrivateProfileString 函数去读取,只要将获取的字符串转换为整型就可以了。其中,GetPrivateProfileInt 函数也是先调用获取字符串,然后再转换为整型,所以,GetPrivateProfileInt 函数是对 GetPrivateProfileString 函数的封装和拓展。
# 程序测试
1我们直接运行程序,则成功从INI文件中获取数据并显示出来,同时目录下有 Config.ini 文件生成,打开文件可以查看里面的数据内容。
![](http://www.writebug.com/myres/static/uploads/2021/10/19/a988bf2a2a94ae1b53168084ffe94717.writebug)
# 总结
要注意的是,上面 3 个函数的INI文件路径最好都写上绝对路径,否则系统会自动在Windows目录中搜索,这样,会导致文件数据读取失败。