首页 > 系统相关 >一文告诉你Linux下如何用C语言实现ini配置文件的解析和保存

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

时间:2025-01-20 21:43:01浏览次数:1  
标签:配置文件 dictionary section iniparser C语言 char ini key Linux

嵌入式项目开发中,会有很多功能模块需要频繁修改参数,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

标签:配置文件,dictionary,section,iniparser,C语言,char,ini,key,Linux
From: https://www.cnblogs.com/yikoulinux/p/18682548

相关文章

  • linux系统安装vmware workstation
    linux系统安装vmwareworkstation1.下载vmwareworkstation2.安装vmwareworkstation(使用root用户)1.解压2.安装3.启动vmwareworkstation1.下载vmwareworkstation访问https://softwareupdate.vmware.com/cds/vmw-desktop/ws/17.6.2/24409262/linux/core/链接下载......
  • C语言逆序操作数组和引用传递参数
    ////main.c//Test_C////Createdbystevexiaohuzhaoon2025/1/20.//#include<stdio.h>//C语言指针传递参数(引用传递)voidswap(int*px,int*py){intt=*px;*px=*py;*py=t;}voidtest(intn){intx=1;for(inti......
  • C语言实现顺序存储线性表
    ////Createdbystevexiaohuzhaoon2025/1/20.///****线性表的顺序存储结构实现*特点:逻辑上相邻的元素,物理上也相邻**/#include<stdio.h>#include<stdlib.h>#defineMAXSIZE100//定义线性表的最大长度//1.定义图书结构体Booktypedefstr......
  • linux 将自定义程序做成服务开机自启动
    在linux系统中有很多方式可以将自定义程序设置成开机自启动,本文所述的方式是通过将程序设置成service来实现自启动。在/lib/systemd/system目录下新建hello.service文件touch/lib/systemd/system/hello.servicevim/lib/systemd/system/hello.service[Unit]Descrip......
  • 你有在linux下编程过吗?有使用过mac系统吗?说下它和win系统的区别?
    关于Linux下编程我有在Linux环境下进行编程的经历。Linux系统以其稳定性、安全性和开源性受到技术人员的青睐。在前端开发方面,Linux提供了强大的工具链和开发环境,如编译器、调试器和版本控制工具,这些都有助于高效地进行Web前端开发。此外,Linux下的前端开发还可以利用诸如Prepros......
  • Linux基础操作(03)文件操作
    文件操作指令cat/more/less/head/tailcat:查看文件的内容执行权限:所有用户语法:cat[选项]文件选项:-n:显示文件行号范例:cat/pron/cpuinfocat-n/pron/cupinfomore:分页查看文件内容执行权限:所有用户语法:more文件/文件路径操作:空格键:向下翻动......
  • Linux平台生成AWR报告
    在Linux平台上生成AWR(AutomaticWorkloadRepository)报告通常是指针对Oracle数据库的操作。AWR报告是Oracle数据库性能诊断的一个重要工具,它可以帮助DBA分析数据库在一段时间内的性能表现。以下是生成AWR报告的一般步骤:1.确认Oracle数据库环境确保Oracle数据库已经安装,并且......
  • linux 设备驱动模型
    作者:baron个人网站:baron-z.cn    Linux设备模型的核心是使用Bus、Class、Device、Driver四个核心数据结构,将大量的、不同功能的硬件设备(以及驱动该硬件设备的方法),以树状结构的形式,进行归纳、抽象,从而方便Kernel的统一管理。学习平台mt8768,内核版本kernel-4.9一、kobjec......
  • Linux常用命令-LVM逻辑卷管理
    Extend扩展vgextendlvextendReduce减少vgreducelvreduce1、PV物理卷管理1.1)、pvscan命令pvscan用于扫描系统中的所有物理卷,并输出相关信息。  1.2)、pvcreate命令pvcreate用于将分区或整个硬盘转换成物理卷,主要是添加LVM属性信息并划分PE存储单位。该命令需要使用硬盘......
  • Linux 常用操作命令大全
    目录一、基础知识1.1Linux系统的文件二、基础操作2.1重启系统2.2关闭系统切换用户(su)三、目录/文件操作3.1切换目录(cd)3.2查看目录(ls)3.3创建目录(mkdir)3.4删除/文件(rm)3.5修改(重命名)目录/文件(mv)3.6拷贝目录/文件(cp)3.7搜索/文件(find)3.8查看当前目录(pwd)四、文件操作4.1新......