INI配置文件解析C函数库

ini是Windows上较常用的小型配置文件,并且windows api提供方便的函数供应用程序读写配置,可惜linux等其它操作系统上的需要用其它的方式.
我这儿写ini配置库是可以跨平台使用的,对于需要跨平台但使用相同配置的应用来说是个不错的选择.
支持符合windows ini标准的配置文件.
有趣兴的朋友可以拿去研究研究.

[2012-2-9日最新更新]

感谢前段时间一个网友提到程序的一些Bug,已修正程序,这次亲自在windows和linux下测试.已经支持GBK,UTF-8编码的ini文件解析。

/**
 * INI配置文件管理函数库
 * Ini file parse functions.
 * By Hoverlees http://www.hoverlees.com me[at]hoverlees.com
 */

#ifndef _HOVERLEES_INI_CONFIG_H
#define _HOVERLEES_INI_CONFIG_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
//#include <unistd.h>

typedef struct _CONFIG_BTREE_NODE{
	char*	key;
	void*	data;
	struct _CONFIG_BTREE_NODE* left;
	struct _CONFIG_BTREE_NODE* right;
	char mem[2];
}CONFIG_BTREE_NODE;

typedef struct _CONFIG_BTREE{
	int numNodes;
	CONFIG_BTREE_NODE* root;
}CONFIG_BTREE;

typedef CONFIG_BTREE INI_CONFIG;

typedef int (*CONFIG_BTREE_TRAVERSE_CB)(CONFIG_BTREE_NODE* node);
typedef int (*CONFIG_BTREE_SAVE_TRAVERSE_CB)(FILE* fp,CONFIG_BTREE_NODE* node);

/**
 * ini内容解析函数,从字符串解析配置
 * @param str 字符串
 * @param slen 字符串长度,可以为0,如果为0,函数自动计算字符串长度
 * @param isGBK 如果ini文件使用GBK字符集,设置成1,否则设置成0
 * @return 成功返回INI_CONFIG指针,失败返回null
 */
INI_CONFIG* ini_config_create_from_string(unsigned char* str,int slen,int isGBK);

/**
 * ini内容解析函数,从文件解析配置
 * @param filename 配置文件名
 * @param isGBK 如果ini文件使用GBK字符集,设置成1,否则设置成0
 * @return 成功返回INI_CONFIG指针,失败返回null
 */
INI_CONFIG* ini_config_create_from_file(const char* filename,int isGBK);

/**
 * 配置释放函数,释放所占用的内存及数据结构
 * @param config 配置对象指针
 * @return 成功返回1,失败返回0
 */
void ini_config_destroy(INI_CONFIG* config);
/**
 * 获取配置整数值
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param default_int 默认值
 * @return 如果配置中有此键对应的值,返回该值,否则返回参数指定的默认值
 */
int ini_config_get_int(INI_CONFIG* config,const char* section,const char* key,int default_int);
/**
 * 获取配置字符串值
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param default_string 默认值
 * @return 如果配置中有此键对应的值,返回该值,否则返回参数指定的默认值
 */
char* ini_config_get_string(INI_CONFIG* config,const char* section,const char* key,char* default_string);
/**
 * 设置变量
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param key_len 键长
 * @param value 值
 * @param value_len 值长度
 * @return 成功为1,失败为0
 */
int ini_config_set_string(INI_CONFIG* config,const char* section,const char* key,int key_len,const char* value,int value_len);
/**
 * 设置变量
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param key_len 键长
 * @param value 整数值
 * @return 成功为1,失败为0
 */
int ini_config_set_int(INI_CONFIG* config,const char* section,const char* key,int key_len,int value);
/**
 * 保存配置到文件中 *提示,原先配置文件中的注释信息将不会保存.
 * @param config 配置对象指针
 * @param filename 保存到的文件
 * @return 成功为1,失败为0
 */
int ini_config_save(INI_CONFIG* config,const char* filename);
/**
 * 类似于ini_config_save,只是参数是文件指针,此函数可以直接使用stdin,stdout,stderr. *提示:本函数不负责关闭fp.
 * @param config 配置对象指针
 * @param fp 文件指针
 * @return 成功为1,失败为0
 */
int ini_config_print(INI_CONFIG* config,FILE* fp);

#endif

下面是调用示例:

#include "confile.h"

void main(int argc,char* argv[]){
	INI_CONFIG* config;
	printf("------------test1-----------\n");
	config=ini_config_create_from_string("hover     =      lees       \n data =    7 \n maxthread=255\n;this is a comment line\r\nyahoo    =alibaba     \n     [section1]   \nhover   =  lees2  \nhover=lees333\n\n hover = lees4444\nyahoo=3\n\n\n",0,0);
	if(config){
		ini_config_print(config,stdout);
		ini_config_destroy(config);
	}

	printf("\n------------test2-----------\n");
	config=ini_config_create_from_file("php.ini",0);
	if(config){
		printf(
			"%s %s\n",
			ini_config_get_string(config,"soap","soap.wsdl_cache_dir","/nodir"),
			ini_config_get_string(config,"soap","soap.wsdl_cache_ttl","xixi")
		);
		ini_config_destroy(config);
	}
}

本例执行结果:

hover@hover-laptop:~/Desktop/c/inifile$ ./test
------------test1-----------
[default]
data=7
hover=lees
maxthread=255
yahoo=alibaba
[section1]
hover=lees4444
yahoo=3

------------test2-----------
2000 On

原代码在这里: 注意代码的编码是UTF-8的,因为本人在linux下开发的.如果要在windows下使用,请转换成GBK先.否则中文注释可能影响到代码.
confile.h confile.c

/**
* INI配置文件管理函数库
* Ini file parse functions.
* By Hoverlees http://www.hoverlees.com me[at]hoverlees.com
*/

#ifndef _HOVERLEES_INI_CONFIG_H
#define _HOVERLEES_INI_CONFIG_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
//#include <unistd.h>

typedef struct _CONFIG_BTREE_NODE{
char*    key;
void*    data;
struct _CONFIG_BTREE_NODE* left;
struct _CONFIG_BTREE_NODE* right;
char mem[2];
}CONFIG_BTREE_NODE;

typedef struct _CONFIG_BTREE{
int numNodes;
CONFIG_BTREE_NODE* root;
}CONFIG_BTREE;

typedef CONFIG_BTREE INI_CONFIG;

typedef int (*CONFIG_BTREE_TRAVERSE_CB)(CONFIG_BTREE_NODE* node);
typedef int (*CONFIG_BTREE_SAVE_TRAVERSE_CB)(FILE* fp,CONFIG_BTREE_NODE* node);

/**
* ini内容解析函数,从字符串解析配置
* @param str 字符串
* @param slen 字符串长度,可以为0,如果为0,函数自动计算字符串长度
* @param isGBK 如果ini文件使用GBK字符集,设置成1,否则设置成0
* @return 成功返回INI_CONFIG指针,失败返回null
*/
INI_CONFIG* ini_config_create_from_string(unsigned char* str,int slen,int isGBK);

/**
* ini内容解析函数,从文件解析配置
* @param filename 配置文件名
* @param isGBK 如果ini文件使用GBK字符集,设置成1,否则设置成0
* @return 成功返回INI_CONFIG指针,失败返回null
*/
INI_CONFIG* ini_config_create_from_file(const char* filename,int isGBK);

/**
* 配置释放函数,释放所占用的内存及数据结构
* @param config 配置对象指针
* @return 成功返回1,失败返回0
*/
void ini_config_destroy(INI_CONFIG* config);
/**
* 获取配置整数值
* @param config 配置对象指针
* @param section 段名,没有段名时可以为NULL
* @param key 键名
* @param default_int 默认值
* @return 如果配置中有此键对应的值,返回该值,否则返回参数指定的默认值
*/
int ini_config_get_int(INI_CONFIG* config,const char* section,const char* key,int default_int);
/**
* 获取配置字符串值
* @param config 配置对象指针
* @param section 段名,没有段名时可以为NULL
* @param key 键名
* @param default_string 默认值
* @return 如果配置中有此键对应的值,返回该值,否则返回参数指定的默认值
*/
char* ini_config_get_string(INI_CONFIG* config,const char* section,const char* key,char* default_string);
/**
* 设置变量
* @param config 配置对象指针
* @param section 段名,没有段名时可以为NULL
* @param key 键名
* @param key_len 键长
* @param value 值
* @param value_len 值长度
* @return 成功为1,失败为0
*/
int ini_config_set_string(INI_CONFIG* config,const char* section,const char* key,int key_len,const char* value,int value_len);
/**
* 设置变量
* @param config 配置对象指针
* @param section 段名,没有段名时可以为NULL
* @param key 键名
* @param key_len 键长
* @param value 整数值
* @return 成功为1,失败为0
*/
int ini_config_set_int(INI_CONFIG* config,const char* section,const char* key,int key_len,int value);
/**
* 保存配置到文件中 *提示,原先配置文件中的注释信息将不会保存.
* @param config 配置对象指针
* @param filename 保存到的文件
* @return 成功为1,失败为0
*/
int ini_config_save(INI_CONFIG* config,const char* filename);
/**
* 类似于ini_config_save,只是参数是文件指针,此函数可以直接使用stdin,stdout,stderr. *提示:本函数不负责关闭fp.
* @param config 配置对象指针
* @param fp 文件指针
* @return 成功为1,失败为0
*/
int ini_config_print(INI_CONFIG* config,FILE* fp);

#endif

Join the Conversation

16 Comments

Your email address will not be published. Required fields are marked *

  1. 好文章,感谢分享
    将ini配置文件抽象成BTree,我肯定是想不到的
    看来我要学习要思考的东西还很多啊

  2. 嗨! 我测试了下你写的这个代发现 读文件的时候返回的总是默认的变量。而且ini文件中dedault字段一直会存在。

  3. 这份代码就可以直接在windows上编译。你也可以考虑直接用windows的ini的函数

  4. 请问有没有可以在windows系统下使用的头文件和源文件,能发我邮箱一份吗,有点急用,多谢!

  5. 你好,少量的你可以使用简单字符串搜索方法,如strstr,kmp,sunday等,大量的需要自己建立索引表,索引表的建立多种多样,这个关键就要看需求了。

  6. 请问下你有没有能够根据关键字,来存储和取出多行数据的相关代码或者方法,有的话能发我邮箱一份吗?多谢

  7. ini文件的规范也是不能使用多行作为值吧,至少我写的这个不能这样。
    你可以自己加escape,如\n表示换行,\\表示原始\

  8. 使用这些函数,发现一个问题,往配置文件里存东西的时候,可能有多行,但是读取的时候只能读出一行数据,其他的读不出来,这个问题怎么解决?谢谢

  9. 对对,我当时没有考虑到,我有空去修正这个问题。谢谢朋友的指出。
    如果朋友急着要使用这个库,可以在我的跳转函数中判断当前字节是否大于127,如果大于,则再读一个字节,并将这两个字节当成一个字符来处理(GBK),如果第二个字节还是大于127,那么再读一个字节,并把这三个字节点一个字符处理(UTF-8),这样可以解决中文问题。