环境
windows 10 64bit
Clion 2023.1
ini简介
ini
文件格式是一种用于保存配置信息的简单文本格式。它通常由多个节(section
)组成,每个节包含多个键值对(key-value pair
)。
下面是 ini
文件的基本语法规则
一个
ini
文件由多个节组成,每个节用方括号([])括起来节后面可以跟一个或多个键值对,每个键值对占一行,格式为
key=value
键值对中,键(
key
)和值(value
)之间用等号(=
)分隔,键和值之间可以有空格。键和值都是字符串,可以包含任何字符,但是如果键或值中包含等号(=
)或分号(;
)这样的特殊字符,需要进行转义注释以井号(
#
)或分号(;
)开头,注释可以出现在任何位置,包括行首、行尾或键值对之间
下面是一个 ini
示例文件,后面代码也会去解析它
# 服务器配置
[server]
ip = 192.168.1.100
port = 8080
;数据库配置
[database]
host = localhost
port = 3306
username = username
password = password
在这个示例文件中,有两个节:server
和 database
。server
包含2个键值对:ip
和 port
,而 database
包含4个键值对,host
、port
、username
和 password
。最后,还有2行注释,一行以 #
开头,另一行以 ;
开头。
代码示例
这里使用 Clion
集成开发环境,编译器使用自带的 MinGW
,首先创建一个 C
可执行项目,命名为 Demo
创建完成后,添加一个头文件 ini_parser.h
,内容如下
#ifndef DEMO_INI_PARSER_H
#define DEMO_INI_PARSER_H
#include <stdio.h>
#include <string.h>
// 获取key对应的值
int GetIniKeyString(char *section,char *key,char *filename,char *buf);
// 修改key对应的值
int PutIniKeyString(char *section,char *key,char *val,char *filename);
#endif //DEMO_INI_PARSER_H
接着新建一个 C
源码文件 ini_parser.c
,内容如下
#include <stdio.h>
#include <string.h>
#include "errno.h"
/*
* 参数:
* section: 配置文件中的节sectin
* key: 配置项的标识
* filename: ini配置文件路径
*
* 返回值: 找到需要的值返回结果0,否则返回-1
*/
int GetIniKeyString(char *section, char *key, char *filename, char *buf)
{
FILE *fp;
// 用来标记是否找到section
int flag = 0;
char sSection[64], *wTmp;
char sLine[1024];
// 节section字符串
sprintf(sSection, "[%s]", section);
if (NULL == (fp = fopen(filename, "r")))
{
printf("open %s failed.\n", filename);
return -1;
}
// 读取ini中的每一行
while (NULL != fgets(sLine, 1024, fp))
{
// 处理ini文件中的注释行
if ('#' == sLine[0])
continue;
if (';' == sLine[0])
continue;
// 定位=的位置
wTmp = strchr(sLine, '=');
if ((NULL != wTmp) && (1 == flag))
{
if (0 == strncmp(key, sLine, strlen(key)))
{
sLine[strlen(sLine) - 1] = '\0';
while (*(wTmp + 1) == ' ')
{
wTmp++;
}
// 获取key对应的value
strcpy(buf, wTmp + 1);
fclose(fp);
return 0;
}
}
else
{
if (0 == strncmp(sSection, sLine, strlen(sSection)))
{
// 不存在键值对的情况下,标记flag
flag = 1;
}
}
}
fclose(fp);
return -1;
}
/*
* 参数:
* section: 配置文件中的节sectin
* key: 配置项的标识
* val: 配置项标识对应的值
* filename: ini配置文件路径
*
* 返回值: 成功返回结果0,否则返回-1
*/
int PutIniKeyString(char *section, char *key, char *val, char *filename)
{
FILE *fpr, *fpw;
int flag = 0;
int ret;
char sLine[1024], sSection[32], *wTmp;
sprintf(sSection, "[%s]", section);
if (NULL == (fpr = fopen(filename, "r")))
return -1;
// 临时文件名
sprintf(sLine, "%s.tmp", filename);
fpw = fopen(sLine, "w");
if (NULL == fpw)
return -1;
while (NULL != fgets(sLine, 1024, fpr))
{
if (2 != flag)
{
wTmp = strchr(sLine, '=');
if ((NULL != wTmp) && (1 == flag))
{
if (0 == strncmp(key, sLine, strlen(key)))
{
// 找到对应的key
flag = 2;
sprintf(wTmp + 1, " %s\n", val);
}
}
else
{
if (0 == strncmp(sSection, sLine, strlen(sSection)))
{
// 找到section的位置
flag = 1;
}
}
}
// 写入临时文件
fputs(sLine, fpw);
}
fclose(fpr);
fclose(fpw);
sprintf(sLine, "%s.tmp", filename);
// rename函数在windows上和linux上表现有差异,看文章中的备注
ret = rename(sLine, filename);
if (ret != 0)
{
if (errno == EEXIST)
{
// 如果目标文件已经存在,需要先删除,再重命名
if (remove(filename) == 0)
{
if (rename(sLine, filename) == 0)
{
// printf("File %s has been renamed to %s\n", sLine, filename);
return 0;
}
}
}
}
return ret;
}
最后编辑工程入口文件 main.c
#include <stdio.h>
#include "ini_parser.h"
int main(int argc, char const *argv[]) {
char buff[128];
int ret;
ret = GetIniKeyString("server", "ip", "config.ini", buff);
printf("get ret:%d,value: %s\n", ret, buff);
memset(buff, 0, sizeof(buff));
ret = GetIniKeyString("database", "db", "config.ini", buff);
printf("get ret:%d, value: %s\n", ret, buff);
ret = PutIniKeyString("server", "port", "80", "config.ini");
printf("put ret:%d\n", ret);
memset(buff, 0, sizeof(buff));
ret = GetIniKeyString("server", "port", "config.ini", buff);
printf("get ret:%d, value: %s\n", ret, buff);
return 0;
}
使用 IDE
的好处就是,在添加各个文件时,它会帮你修改 CMakeLists.txt
,不需要自己手动去添加
cmake_minimum_required(VERSION 3.25)
project(Demo C)
set(CMAKE_C_STANDARD 99)
add_executable(Demo main.c ini_parser.h ini_parser.c)
然后,就可以编译整个工程了,选中 IDE
顶部菜单栏中的 Build
--> Build Project
,完成后,会在目录 cmake-build-debug
下生成可执行文件 Demo.exe
,在运行之前,还需要将配置 config.ini
(也就是上文提到的ini示例文件) 也放到 cmake-build-debug
下
最后,按下快捷键 Shift+F10
来运行一下
备注
rename
方法在 windows
和 linux
上的表现不一样,如果目标文件存在,linux
可以直接覆盖。但是,在 windows
上,返回值就是-1,errno
提示 File Exists
。
参考资料
https://www.w3resource.com/c-programming/stdio/c_library_method_rename.php