击左上方蓝色“一口Linux”,选择“设为星标”
第一时间看干货文章 ☞【干货】嵌入式驱动工程师学习路线 ☞【干货】Linux嵌入式知识点-思维导图-免费获取 ☞【就业】一个可以写到简历的基于Linux物联网综合项目 ☞【就业】找工作简历模版
嵌入式项目开发中,会有很多功能模块需要频繁修改参数,Linux下我们可以通过ini格式的文件保存配置信息。
本文通过开源库iniparser,详细讲解如何用C语言实现ini文件的参数解析和配置保存。
本文代码实例获取方式见文末。
节(Section):
INI文件中的各个部分通过方括号 [] 包裹的名称来定义,例如 **[Section1]**。每个节可以包含多个键值对。
键值对(Key-Value Pairs):
键和值之间用等号 = 分隔,如 key1=value1。键通常是描述性质的字符串,而值则可以是字符串、数字或其他类型的数据。
注释:
注释行以分号 ; 开始,直到行尾都被视为注释内容,不会被程序解析。
多行值:
某些INI解析器允许值跨越多行,通常通过在行尾添加反斜杠 \ 来延续到下一行
;author yikoupeng
[BASIC_INFO]
version = V1.1.1.1
user = yikou
number = 999
[FTP]
ftppath = /home/ftp
ftpuser = ftp
ftppass = 123456
port = 21
......
其中:
注意:
每个组下的key是唯一不能重复的,但不同组下可以存在相同的key.
iniparser是一个C语言库,用于解析和操作 INI 格式的配置文件,是针对INI文件的开源解析器。
iniparser可以对配置文件进行解析、添加、修改、删除等操作。
git地址如下:
https://github.com/ndevilla/iniparser
1、下载iniparser
wget https://codeload.github.com/ndevilla/iniparser/tar.gz/refs/tags/v4.1 -O iniparserv4.1.tar.gz
2、解压
tar -zxvf iniparserv4.1.tar.gz
3、进入目录
cd iniparser-4.1/
peng@ubuntu:~/work/iniparser-4.1$ ls
AUTHORS doc example FAQ-en.md FAQ-zhcn.md html INSTALL libiniparser.a libiniparser.so.1 LICENSE Makefile README.md src test
4、进入src文件夹可以看到我们所需要的主要代码
peng@ubuntu:~/work/iniparser-4.1$ cd src/
peng@ubuntu:~/work/fdw/code/config/iniparser-4.1/src$ ls
dictionary.c dictionary.h iniparser.c iniparser.h
如果想移植该程序到我们的项目中,只需要将这几个文件添加到工程对应目录,编译进工程即可。
dictionary.h里面声明了一些直接解析ini file的API,iniparser.h头文件里面声明了一些提供用户操作的API。
iniparser.h里面的API是对dictionary.h里面API的再次封装,以提供用户友好性。
iniparser.h头文件里面的主要API
/*
* @brief 从ini格式的配置文件中加载数据
* @param [IN] ininame 要打开的ini格式文件
* @return != NULL 返回一个指向dictionary结构的指针
* == NULL 加载ini文件失败
*/
dictionary * iniparser_load(const char *ininame);
/*
* @brief 获取指定键(key)对应的字符串类型的值
* @param [IN] d dictionary结构的指针
* @param [IN] key 要查找的键,通常格式为 "section:key",表示要获取哪个节(section)下的哪一项(key)的值。
* @param [IN] def 当键不存在或者其值不是字符串时的默认返回值。如果没有找到对应键,函数将返回此默认值。
* @return 如果找到了相应的键,返回键值对应字符串
* 如果没有找到匹配的键,返回def指定的字符串值
*/
const char * iniparser_getstring(const dictionary *d, const char *key, const char *def);
/*
* @brief 获取指定键(key)对应的整数值
* @param [IN] d dictionary结构的指针
* @param [IN] key 要查找的键,通常格式为 "section:key",表示要获取哪个节(section)下的哪一项(key)的值。
* @param [IN] notfound 当键不存在或者其值不能被转换为整数时,函数将返回这个默认值。
* @return 如果找到了相应的键,并且其值可以被成功转换为整数,则返回该整数值。
* 如果没有找到匹配的键,或者该键对应的值无法转换为整数,则返回 notfound 参数提供的默认值。
*/
int iniparser_getint(const dictionary * d, const char * key, int notfound);
/*
* @brief 获取指定键(key)对应的浮点型值
* @param [IN] d dictionary结构的指针
* @param [IN] key 要查找的键,通常格式为 "section:key",表示要获取哪个节(section)下的哪一项(key)的值。
* @param [IN] notfound 当键不存在或者其值无法转换为双精度浮点数时,函数返回的默认值。
* @return 如果找到了相应的键,并且其值能成功转换为一个双精度浮点数,则返回该浮点数。
* 如果没有找到匹配的键,或者键的值不能被解释为一个有效的双精度浮点数,则返回 notfound 参数所提供的默认值。
*/
double iniparser_getdouble(const dictionary *d, const char *key, double notfound);
/*
* @brief 设置或修改 ini 配置文件中某个键值对
* @param [IN] d dictionary结构的指针
* @param [IN] entry 字符串形式的键值对标识符,格式通常是 "section:key",表明您要在哪个节(section)下的哪个键(key)上设置或修改值(val)。
* key值存在则修改对应val,key值不存在则会新增
* @param [IN] val: 要设置的新值,作为字符串传递。
* @return 返回0表示设置成功
*/
int iniparser_set(dictionary *ini, const char *entry, const char *val);
/*
* @brief 移除 ini 配置文件中某个键值对
* @param [IN] d dictionary结构的指针
* @param [IN] entry 字符串形式的键名,包括可选的部分名称(section)和键(key)
* 如果不指定key,则会移除整个section
*/
void iniparser_unset(ini, const char *entry);
/*
* @brief 判断 ini 配置文件是否存在某个键值
* @param [IN] d dictionary结构的指针
* @param [IN] entry 字符串形式的键值对标识符,格式通常是 "section:key"
* @return 返回1表示存在,返回0表示不存在
*/
int iniparser_find_entry(const dictionary *ini, const char *entry);
/*
* @brief 获取ini配置文件中section的数量
* @param [IN] d dictionary结构的指针
* @return 成功返回section个数,失败返回 -1
*/
int iniparser_getnsec(const dictionary * d);
/*
* @brief 获取某个section值
* @param [IN] d dictionary结构的指针
* @param [IN] n 指定获取第几个section值
* @return 成功返回获取到的section值,失败返回NULL
*/
const char *iniparser_getsecname(const dictionary * d, int n);
/*
* @brief 获取ini配置文件中某个section的key个数
* @param [IN] d dictionary结构的指针
* @param [IN] s section
* @return 返回指定section下的key个数
*/
int iniparser_getsecnkeys(dictionary * d, char * s);
/*
* @brief 获取ini配置文件中某个section的所有key
* @param [IN] d dictionary结构的指针
* @param [IN] s section
* @param [OUT] keys 通过这个参数输出key,也可以通过返回值获取
* @return 成功返回指定section下的key,失败返回NULL
*/
const char **iniparser_getseckeys(const dictionary *d, const char *s, const char **keys)
/*
* @brief 保存dictionary对象到文件中
* @param [IN] d dictionary结构的指针
* @param [IN] f 已打开的文件描述符
*/
void iniparser_dump_ini(const dictionary *d, FILE *f);
/*
* @brief 释放dictionary对象
* @param [IN] d dictionary结构的指针
*/
void iniparser_freedict(dictionary * d);
//获取dictionary对象的section个数
int iniparser_getnsec(dictionary * d);
//获取dictionary对象的第n个section的名字
char * iniparser_getsecname(dictionary * d, int n);
//保存dictionary对象到file
void iniparser_dump_ini(dictionary * d, FILE * f);
//保存dictionary对象一个section到file
void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f);
//保存dictionary对象到file
void iniparser_dump(dictionary * d, FILE * f);
//获取dictionary对象某个section下的key个数
int iniparser_getsecnkeys(dictionary * d, char * s);
//获取dictionary对象某个section下所有的key
char ** iniparser_getseckeys(dictionary * d, char * s);
//返回dictionary对象的section:key对应的字串值
char * iniparser_getstring(dictionary * d, const char * key, char * def);
//返回idictionary对象的section:key对应的整形值
int iniparser_getint(dictionary * d, const char * key, int notfound);
//返回dictionary对象的section:key对应的双浮点值
double iniparser_getdouble(dictionary * d, const char * key, double notfound);
//返回dictionary对象的section:key对应的布尔值
int iniparser_getboolean(dictionary * d, const char * key, int notfound);
//设置dictionary对象的某个section:key的值
int iniparser_set(dictionary * ini, const char * entry, const char * val);
//删除dictionary对象中某个section:key
void iniparser_unset(dictionary * ini, const char * entry);
//判断dictionary对象中是否存在某个section:key
int iniparser_find_entry(dictionary * ini, const char * entry) ;
//解析dictionary对象并返回(分配内存)dictionary对象
dictionary * iniparser_load(const char * ininame);
//释放dictionary对象(内存)
void iniparser_freedict(dictionary * d);
//计算关键词的hash值
unsigned dictionary_hash(const char * key);
//创建dictionary对象
dictionary * dictionary_new(int size);
//删除dictionary对象
void dictionary_del(dictionary * vd);
//获取dictionary对象的key值
char * dictionary_get(dictionary * d, const char * key, char * def);
//设置dictionary对象的key值
int dictionary_set(dictionary * vd, const char * key, const char * val);
//删除dictionary对象的key值
void dictionary_unset(dictionary * d, const char * key);
//保存dictionary对象
void dictionary_dump(dictionary * d, FILE * out);
编写配置文件:
vim config.ini
[BASIC_INFO]
version = V1.1.1.1
user = yikou
number = 999
[FTP]
ftppath = /home/ftp
ftpuser = ftp
ftppass = 123456
port = 21
[NETWORK]
interface = eth1
dns1 = 8.8.8.8
dns2 = 8.8.8.8
subnet = 255.255.255.0
router = 192.168.3.1
尝试编写iniparser程序对ini文件进行修改:
#include
#include "iniparser.h"
#include "dictionary.h"
#define PATH "config.ini"
typedef unsigned char BYTE;
typedef unsigned char UINT8;
typedef unsigned char UCHAR;
typedef unsigned short int UINT16;
typedef unsigned long int UINT32;
struct device_cfg_s{
/*basicinfo*/
char version[32];
char user[32];
int number;
/*ftp*/
char ftppath[128];
char ftpuser[32];
char ftppass[32];
UINT16 port;
/*network*/
char interface[16];
char dns1[32];
char dns2[32];
char subnet[32];
char router[32];
};
struct device_cfg_s devcfg;
int cfg_load(char *name)
{
dictionary *ini= NULL;
/* 解析dictionary对象并返回(分配内存)dictionary对象*/
ini = iniparser_load(name);
if( ini ==NULL)
{
printf("iniparser failure\n");
return -1;
}
/*basicinfo*/
strcpy(devcfg.version,iniparser_getstring(ini, "BASIC_INFO:version", "v0.0.0.0"));
strcpy(devcfg.user ,iniparser_getstring(ini, "BASIC_INFO:user", "yikou"));
devcfg.number = iniparser_getint(ini, "BASIC_INFO:number", 666);
/*ftp*/
strcpy(devcfg.ftppath ,iniparser_getstring(ini, "FTP:ftppath", "/"));
strcpy(devcfg.ftpuser ,iniparser_getstring(ini, "FTP:ftpuser", "ftp"));
strcpy(devcfg.ftppass ,iniparser_getstring(ini, "FTP:ftppass", "123456"));
devcfg.port = iniparser_getint(ini, "FTP:port", 21);
/*network*/
strcpy(devcfg.interface,iniparser_getstring(ini, "NETWORK:interface", "eth0"));
strcpy(devcfg.dns1,iniparser_getstring(ini, "NETWORK:dns1", NULL));
strcpy(devcfg.dns2 ,iniparser_getstring(ini, "NETWORK:dns2", NULL));
strcpy(devcfg.subnet ,iniparser_getstring(ini, "NETWORK:subnet", "255.255.255.0"));
strcpy(devcfg.router ,iniparser_getstring(ini, "NETWORK:router", "192.168.3.1"));
/* 返回dictionary对象的section,key对应的字串值 */
printf("version:%s\n",devcfg.version);
printf("user:%s\n", devcfg.user);
printf("number:%d\n",devcfg.number);
printf("ftppath:%s\n", devcfg.ftppath);
printf("ftpuser:%s\n",devcfg.ftpuser);
printf("ftppass:%s\n", devcfg.ftppass);
printf("port:%d\n",devcfg.port);
printf("interface:%s\n", devcfg.interface);
printf("dns1:%s\n",devcfg.dns1);
printf("dns2:%s\n", devcfg.dns2);
printf("subnet:%s\n",devcfg.subnet);
printf("router:%s\n", devcfg.router);
iniparser_freedict(ini);
}
int main (int argc, char **argv)
{
cfg_load(PATH);
//cfg_save_key(PATH,"BASIC_INFO","chnAddr","3501");
//cfg_save_key(PATH,"BASIC_INFO","enddeviceNo","87564289");
return 0;
}
可以看到最终值以配置文件中的为准。
如果配置文件没有配置参数则以iniparser_getxxxxx()中默认值为准。
为方便保存键值,彭老师封装了函数
int cfg_save_key(char *filename,char *section,char *key,char *value)
参数:
filename 配置文件名
section 节名字
key 键
value 值
int cfg_save_key(char *filename,char *section,char *key,char *value)
{
FILE *fp = NULL ;
dictionary *ini= NULL;
char item[128]={0};
/* 解析dictionary对象并返回(分配内存)dictionary对象*/
ini = iniparser_load(filename);
if( ini ==NULL)
{
printf("iniparser failure\n");
return -1;
}
sprintf(item,"%s:%s",section,key);
/* 设置dictionary对象的某个section:key的值 */
iniparser_set(ini, item, value);
fp = fopen(filename, "w");
if( fp == NULL ) {
printf("stone:fopen error!\n");
exit(-1);
}
/* 保存dictionary对象 */
// iniparser_dumpsection_ini(ini, "BASIC_INFO", fp);
iniparser_dump_ini(ini, fp);
fclose(fp);
/* 释放dictionary对象(内存)*/
iniparser_freedict(ini);
}
例如我们修改BASIC_INFO节的user的值为yikoupeng,number值为12345
cfg_save_key(PATH,"BASIC_INFO","user","yikoupeng");
cfg_save_key(PATH,"BASIC_INFO","number","12345");
执行结果:可以看到配置文件basic_info节的user 和number 键值对被修改。
后台回复:iniparser
end
一口Linux
关注,回复【1024】海量Linux资料赠送
精彩文章合集
文章推荐