一文告诉你Linux下如何用C语言实现ini配置文件的解析和保存

news/2025/2/28 20:00:06/文章来源:https://www.cnblogs.com/yikoulinux/p/18682548

嵌入式项目开发中,会有很多功能模块需要频繁修改参数,Linux下我们可以通过ini格式的文件保存配置信息。

本文通过开源库iniparser,详细讲解如何用C语言实现ini文件的参数解析和配置保存。

本文代码实例获取方式见文末。

一、ini文件

1 什么是 ini文件

  • INI(Initialization File)文件是一种简单直观的数据存储格式,常用于配置应用程序的初始化设置。这种文件通常包含若干个节(section)和键值对(key-value pairs)。INI文件的每一部分都是自描述性的,易于阅读和编辑,使得非程序员也能轻易理解并修改配置参数。
  • INI文件因其简单易用性而在许多编程语言中广泛应用,尤其是在Windows操作系统中,很多应用程序都采用INI文件作为配置文件。当然,随着XML、JSON等更丰富、更结构化的数据交换格式的普及,INI文件在现代应用程序中的使用相对减少,但在一些轻量级应用或对启动速度有较高要求的情况下,仍然是一种常见且实用的配置文件格式。

2 ini文件结构

  • 节(Section)

    INI文件中的各个部分通过方括号 [] 包裹的名称来定义,例如 [Section1]。每个节可以包含多个键值对。

  • 键值对(Key-Value Pairs)

    键和值之间用等号 = 分隔,如 key1=value1。键通常是描述性质的字符串,而值则可以是字符串、数字或其他类型的数据。

  • 注释

    注释行以分号 ; 开始,直到行尾都被视为注释内容,不会被程序解析。

  • 多行值

    某些INI解析器允许值跨越多行,通常通过在行尾添加反斜杠 \ 来延续到下一行

3 ini文件举例

;author yikoupeng[BASIC_INFO]
version                = V1.1.1.1
user                   = yikou
number                 = 999[FTP]
ftppath                = /home/ftp
ftpuser                = ftp
ftppass                = 123456
port                   = 21......

其中:

  • 注释以分号(;)开头
  • [BASIC_INFO]、[FTP]就是组名,
  • 组成员有“version”........“ftppath”...

注意:

每个组下的key是唯一不能重复的,但不同组下可以存在相同的key.

二、 iniparser库

1. iniparser介绍

iniparser是一个C语言库,用于解析和操作 INI 格式的配置文件,是针对INI文件的开源解析器。

iniparser可以对配置文件进行解析、添加、修改、删除等操作。

git地址如下:

 https://github.com/ndevilla/iniparser

2. 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 

如果想移植该程序到我们的项目中,只需要将这几个文件添加到工程对应目录,编译进工程即可。

三、iniparser API(应用编程程序接口)

dictionary.h里面声明了一些直接解析ini file的API,iniparser.h头文件里面声明了一些提供用户操作的API。

iniparser.h里面的API是对dictionary.h里面API的再次封装,以提供用户友好性。

iniparser.h头文件里面的主要API

1 加载ini文件

/**  @brief  从ini格式的配置文件中加载数据*  @param  [IN]  ininame  要打开的ini格式文件            *  @return != NULL 返回一个指向dictionary结构的指针*          == NULL 加载ini文件失败*/dictionary * iniparser_load(const char *ininame);

2 获取键值

  •   /**  @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);

3 设置键值

/**  @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);

4 移除键值

  • /*
    *  @brief  移除 ini 配置文件中某个键值对
    *  @param  [IN]  d  dictionary结构的指针   
    *  @param  [IN]  entry  字符串形式的键名,包括可选的部分名称(section)和键(key)
    *					     如果不指定key,则会移除整个section
    */
    void iniparser_unset(ini, const char *entry);
    

5 判断键是否存在

  • /*
    *  @brief  判断 ini 配置文件是否存在某个键值
    *  @param  [IN]  d  dictionary结构的指针   
    *  @param  [IN]  entry  字符串形式的键值对标识符,格式通常是 "section:key"
    *  @return 返回1表示存在,返回0表示不存在
    */
    int iniparser_find_entry(const dictionary *ini, const char *entry);
    

6 获取section个数

  • /*
    *  @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);
    

7 获取section下key个数

  • /*
    *  @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)
    

8 保存dictionary对象到文件中

  • /*
    *  @brief  保存dictionary对象到文件中
    *  @param  [IN]  d  dictionary结构的指针   
    *  @param  [IN]  f  已打开的文件描述符
    */
    void iniparser_dump_ini(const dictionary *d, FILE *f);
    

9 释放dictionary对象

  • /*
    *  @brief  释放dictionary对象
    *  @param  [IN]  d  dictionary结构的指针   
    */
    void iniparser_freedict(dictionary * d);
    

10 api汇总

  • iniparser.h头文件里面的API
//获取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);    
  • dictionary.h头文件里面的API
 //计算关键词的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);    

四、 iniparser库C语言操作实例

1、config.ini

编写配置文件:

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

2、读取配置参数

尝试编写iniparser程序对ini文件进行修改:

#include <stdio.h>
#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()中默认值为准。

3、保存配置信息到文件

为方便保存键值,彭老师封装了函数

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的值为yikoupengnumber值为12345

	cfg_save_key(PATH,"BASIC_INFO","user","yikoupeng");cfg_save_key(PATH,"BASIC_INFO","number","12345");

执行结果:

可以看到配置文件basic_info节的usernumber 键值对被修改。

后台回复:iniparser

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/872340.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql的学习

Mysql建立 索引优化: sql优化: 为了解决下面的索引失效问题序列索引优化:

中考英语优秀范文-014 The hero in my heart 我心中的英雄

1 写作要求 自古以来,人们对英雄的定义没有统一的标准。英雄可以是科学家、军人、运动员,也可以是医生、保安或外卖骑手。假如你是学校广播站的一名英语播报员,明天你准备向大家介绍一位你心目中的英雄,请你根据下面的要点提示,写一篇英语广播稿。 1 须包含提示中的所有内…

python 探空数据根据时间偏移量计算具体时间

这里有一组探空数据,每天08时和20时放气球,气球飞上去的时间就是用时间偏移量来计算的,而不是直接显示好的 根据“年”“月”“日”“时”“时间偏移量”列,时间偏移量单位为秒,计算具体的时间 #!/usr/bin/python3 # -*- coding: utf-8 -*- """ @Time : 20…

LaTeX之符号表

本文介绍了在 $\LaTeX{}$ 中常用的符号。\(\LaTeX{}\) 之符号表 目录\(\LaTeX{}\) 之符号表\(\LaTeX{}\) 普通符号文本/数学模式通用符号希腊字母二元关系符二元运算符巨算符数学重音符号箭头作为重音的箭头符号定界符用于行间公式的大定界符其他符号AMS 符号AMS希腊字符和希伯…

【抓包工具】wireshark零基础使用教程

Wireshark是什么 Wireshark是使用最广泛的一款「开源抓包软件」,常用来检测网络问题、攻击溯源、或者分析底层通信机制。 它使用WinPCAP作为接口,直接与网卡进行数据报文交换。 Wireshark抓包原理 Wireshark使用的环境大致分为两种,一种是电脑直连互联网的单机环境,另外一种…

多端响应式

重要!响应式开发 目录重要!响应式开发是什么?怎么实现?媒体媒体查询断点是什么适配方案栅格布局响应式栅格系统实例 是什么? 多终端显示不同,更好看 PC,ipad,手机适配 怎么实现? 媒体查询,断点: 视口宽不同,布局不同 移动端??? 320-480端口 rem 不考虑大尺寸,更…

公共图床-OIER试炼场

公共图床-OIER试炼场 如何使用? 1. 使用浏览器直接访问 https://api-cdn.u1128333.nyat.app:35910/2. 通过插件访问 插件下载点我 MIT License, ©2025 Chan. 在浏览器扩展中添加即可使用。

32. 样式表

一、样式表为了美化窗口或控件的外观,可以通过窗口或控件的调色板给窗口或控件按照角色和分组设置颜色,还可以对窗口或控件的每个部分进行更细致的控制,这涉及窗口或控件的样式表(Qt style sheets, QSS),它是从 HTML 的层叠样式表(cascading style sheets, CSS)演化而来…

TIA SCL编程清除字符串中所有的空格

今天做一个小的练习,这是2025年第一个记录的学习笔记。 在IA新建一个FC,名字叫做TrimSpace,建立以下内部变量:写一段SCL代码: #len := LEN(#str_in);#str_trim_out := ;FOR #i := 1 TO #len DO   IF MID(IN := #str_in, L := 1, P := #i) <> THEN   …