c语言直接读写ini配置文件

时间:2022-07-22
本文章向大家介绍c语言直接读写ini配置文件,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

现场好多地方反馈记录全采出来,无法入库。实际上采集部门专门做有一数据分析入库工具,但不是标准的,每个地方都需要采集部门特殊改。

于是想到自己做一工具,模拟车载机通信,把全采出来的数据通过连接采集前置传至采集本地库。但是遇到一问题,参数和配置如何保存?

windows系统中有一种ini配置文件,可以用它来保存配置。高级语言操作ini文件很简单,有现有的库,但c语言,只能自己做一个了。分享下

C直接操作ini文件源码:

**

 * 文件:inirw.h

 * 版本:1.0

 *

 * 说明:ini配置文件读写

 * 1、支持;和#注释符号,支持行尾注释。

 * 2、支持带引号'或"成对匹配的字符串,提取时自动去引号。引号中可带其它引号或;#注释符。

 * 3、支持无section或空section(名称为空)。

 * 4、支持10、16、8进制数,0x开头为16进制数,0开头为8进制。

 * 5、支持section、key或=号前后带空格。

 * 6、支持n、r、rn或nr换行格式。

 * 7、不区分section、key大小写,但写入时以新串为准,并保持其大小写。

 * 8、新增数据时,若section存在则在该节最后一个有效数据后添加,否则在文件尾部添加。

 * 9、支持指定key所在整行删除,即删除该键值,包括注释。

 * 10、可自动跳过格式错误行,修改时仍然保留。

 * 11、修改时保留原注释:包括整行注释、行尾注释(包括前面空格)。

 * 12、修改时保留原空行。以上三点主要是尽量保留原格式。

 */

 

inirw.h头文件:

#ifndef _INI_RW_H_

#define _INI_RW_H_


#ifdef __cplusplus

extern "C" {

#endif


//加载ini文件至内存

int iniFileLoad(const char *filename);

//释放ini文件所占资源

void iniFileFree();


//获取字符串,不带引号

int iniGetString(const char *section, const char *key, char *value, int size, const char *defvalue);

//获取整数值

int iniGetInt(const char *section, const char *key, int defvalue);

//获取浮点数

double iniGetDouble(const char *section, const char *key, double defvalue);


//设置字符串:若value为NULL,则删除该key所在行,包括注释

int iniSetString(const char *section, const char *key, const char *value);

//设置整数值:base取值10、16、8,分别表示10、16、8进制,缺省为10进制

int iniSetInt(const char *section, const char *key, int value, int base);


#ifdef __cplusplus

}

#endif


#endif


inirw.c文件:

#include <ctype.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


#define SIZE_LINE		1024	//每行最大长度

#define SIZE_FILENAME	256		//文件名最大长度


#define min(x, y)		(x <= y) ? x : y


typedef enum _ELineType_ {

    LINE_IDLE,		//未处理行

	LINE_ERROR,		//错误行

	LINE_EMPTY,		//空白行或注释行

	LINE_SECTION,	//节定义行

	LINE_VALUE		//值定义行

} ELineType ;



static char gFilename[SIZE_FILENAME];

static char *gBuffer;

static int gBuflen;



//去除串首尾空格,原串被改写

static char *StrStrip(char *s)

{

	size_t size;

	char *p1, *p2;


	size = strlen(s);

	if (!size)

		return s;


	p2 = s + size - 1;


	while ((p2 >= s) && isspace(*p2))

		p2 --;

	*(p2 + 1) = '';


	p1 = s;

	while (*p1 && isspace(*p1))

		p1 ++;

	if (s != p1)

		memmove(s, p1, p2 - p1 + 2);

	return s;

}



//不区分大小写比较字符串

static int StriCmp(const char *s1, const char *s2)

{

	int ch1, ch2;

	do

	{

		ch1 = (unsigned char)*(s1++);

		if ((ch1 >= 'A') && (ch1 <= 'Z'))

			ch1 += 0x20;


		ch2 = (unsigned char)*(s2++);

		if ((ch2 >= 'A') && (ch2 <= 'Z'))

			ch2 += 0x20;

	} while ( ch1 && (ch1 == ch2) );

	return(ch1 - ch2);

}



//取一行

//输入:数据区(指针及长度)

//输出:行类型、有效内容串(去首尾空格)、注释首、注释尾、下一行首(行尾与下一行首间为换行符)

//      有效内容位置为[buf, rem1)

static int GetLine(char *buf, int buflen, char *content, char **rem1, char **rem2, char **nextline)

{

	char *cont1, *cont2;

	int cntblank, cntCR, cntLF;		//连续空格、换行符数量

	char isQuot1, isQuot2;			//引号

	int i;

	char *p;


	//首先断行断注释,支持如下换行符:r、n、rn、nr

	cntblank = 0;

	cntCR = cntLF = 0;

	isQuot1 = isQuot2 = 0;

	cont1 = *rem1 = 0;

	content[0] = 0;

	for (i = 0, p = buf; i < buflen; i ++, p ++)

	{

		if (*p == 0) {

			p ++;

			break;

		}

		//2个CR或LF,行结束

		if (cntCR == 2 || cntLF == 2) {

			p --;	//回溯1

			break;

		}

		//CR或LF各1个之后任意字符,行结束

		if (cntCR + cntLF >= 2) {

			break;

		}

		//CR或LF之后出现其它字符,行结束

		if ((cntCR || cntLF) && *p != 'r' && *p != 'n')

			break;


		switch (*p) {

		case 'r':

			cntCR ++;

			break;

		case 'n':

			cntLF ++;

			break;

		case ''':

			if (!isQuot2)

				isQuot1 = 1 - isQuot1;

			break;

		case '"':

			if (!isQuot1)

				isQuot2 = 1 - isQuot2;

			break;

		case ';':

		case '#':

			if (isQuot1 || isQuot2)

				break;

			if (*rem1 == NULL)

				*rem1 = p - cntblank;

			break;

		default:

			if (isspace((unsigned char)*p)) {

				cntblank ++;

			} else {

				cntblank = 0;

				if ((*rem1 == NULL) && (cont1 == NULL))

					cont1 = p;

			}

			break;

		}

	}


	*nextline = p;

	*rem2 = p - cntCR - cntLF;

	if (*rem1 == NULL)

		*rem1 = *rem2;

	cont2 = *rem1 - cntblank;


	if (cont1 == NULL) {

		cont1 = cont2;

		return LINE_EMPTY;

	}


	i = (int)(cont2 - cont1);

	if (i >= SIZE_LINE)

		return LINE_ERROR;


	//内容头尾已无空格

	memcpy(content, cont1, i);

	content[i] = 0;


	if (content[0] == '[' && content[i - 1] == ']')

		return LINE_SECTION;

	if (strchr(content, '=') != NULL)

		return LINE_VALUE;

	

	return LINE_ERROR;

}



//取一节section

//输入:节名称

//输出:成功与否、节名称首、节名称尾、节内容首、节内容尾(含换行)、下一节首(节尾与下一节首间为空行或注释行)

static int FindSection(const char *section, char **sect1, char **sect2, char **cont1, char **cont2, char **nextsect)

{

	int type;

	char content[SIZE_LINE];

	char *rem1, *rem2, *nextline;


	char *p;

	char *empty;

	int uselen = 0;

	char found = 0;


	if (gBuffer == NULL) {

		return 0;

	}


	while (gBuflen - uselen > 0) {

		p = gBuffer + uselen;

		type = GetLine(p, gBuflen - uselen, content, &rem1, &rem2, &nextline);

		uselen += (int)(nextline - p);


		if (LINE_SECTION == type) {

			if (found || section == NULL) break;		//发现另一section

			content[strlen(content) - 1] = 0;			//去尾部]

			StrStrip(content + 1);						//去首尾空格

			if (StriCmp(content + 1, section) == 0) {

				found = 1;

				*sect1 = p;

				*sect2 = rem1;

				*cont1 = nextline;

			}

			empty = nextline;

		} else

		if (LINE_VALUE == type) {

			if (!found && section == NULL) {

				found = 1;

				*sect1 = p;

				*sect2 = p;

				*cont1 = p;

			}

			empty = nextline;

		}

	}

	

	if (!found) return 0;


	*cont2 = empty;

	*nextsect = nextline;

	return 1;

}



//从一行取键、值

//输入:内容串(将被改写)

//输出:键串、值串

static void GetKeyValue(char *content, char **key, char **value)

{

	char *p;


	p = strchr(content, '=');

	*p = 0;

	StrStrip(content);

	StrStrip(p + 1);

	*key = content;

	*value = p + 1;

}



//释放ini文件所占资源

void iniFileFree()

{

	if (gBuffer != NULL) {

		free(gBuffer);

		gBuffer = 0;

		gBuflen = 0;

	}

}



//加载ini文件至内存

int iniFileLoad(const char *filename)

{

	FILE *file;

	int len;


	iniFileFree();

	if (strlen(filename) >= sizeof(gFilename))

		return 0;

	strcpy(gFilename, filename);


	file = fopen(gFilename, "rb");

	if (file == NULL) 

		return 0;


	fseek(file, 0, SEEK_END);

	len = ftell(file);

	gBuffer = malloc(len);

	if (gBuffer == NULL) {

		fclose(file);

		return 0;

	}


	fseek(file, 0, SEEK_SET);

	len = fread(gBuffer, 1, len, file);

	fclose(file);

	gBuflen = len;

	return 1;

}



//读取值原始串

static int iniGetValue(const char *section, const char *key, char *value, int maxlen, const char *defvalue)

{

	int type;

	char content[SIZE_LINE];

	char *rem1, *rem2, *nextline;

	char *key0, *value0;


	char *p;

	int uselen = 0;

	char found = 0;


	int len;


	if (gBuffer == NULL || key == NULL) {

		if (value != NULL)

			value[0] = 0;

		return 0;

	}


	while (gBuflen - uselen > 0) {

		p = gBuffer + uselen;

		type = GetLine(p, gBuflen - uselen, content, &rem1, &rem2, &nextline);

		uselen += (int)(nextline - p);


		if (LINE_SECTION == type) {

			if (found || section == NULL) break;		//发现另一section

			content[strlen(content) - 1] = 0;			//去尾部]

			StrStrip(content + 1);						//去首尾空格

			if (StriCmp(content + 1, section) == 0) {

				found = 1;

			}

		} else

		if (LINE_VALUE == type) {

			if (!found && section == NULL) {

				found = 1;

			}

			if (!found)

				continue;

			GetKeyValue(content, &key0, &value0);

			if (StriCmp(key0, key) == 0) {

				len = strlen(value0);

				if (len == 0) break;		//空值视为无效

				if (value != NULL) {

					len = min(len, maxlen - 1);

					strncpy(value, value0, len);

					value[len] = 0;

				}

				return 1;

			}

		}

	}

	

	//未发现键值取缺省

	if (value != NULL) {

		if (defvalue != NULL) {

			len = min(strlen(defvalue), maxlen - 1);

			strncpy(value, defvalue, len);

			value[len] = 0;

		} else {

			value[0] = 0;

		}

	}

	return 0;

}



//获取字符串,不带引号

int iniGetString(const char *section, const char *key, char *value, int maxlen, const char *defvalue)

{

	int ret;

	int len;


	ret = iniGetValue(section, key, value, maxlen, defvalue);

	if (!ret)

		return ret;


	//去首尾空格

	len = strlen(value);

	if (value[0] == ''' && value[len - 1] == ''') {

		value[len - 1] = 0;

		memmove(value, value + 1, len - 1);

	} else

	if (value[0] == '"' && value[len - 1] == '"') {

		value[len - 1] = 0;

		memmove(value, value + 1, len - 1);

	}

	return ret;

}



//获取整数值

int iniGetInt(const char *section, const char *key, int defvalue)

{

	char valstr[64];


	if (iniGetValue(section, key, valstr, sizeof(valstr), NULL))

	    return (int)strtol(valstr, NULL, 0);

	return defvalue;

}



//获取浮点数

double iniGetDouble(const char *section, const char *key, double defvalue)

{

	char valstr[64];


	if (iniGetValue(section, key, valstr, sizeof(valstr), NULL))

	    return (int)atof(valstr);

	return defvalue;

}



//设置字符串:若value为NULL,则删除该key所在行,包括注释

int iniSetString(const char *section, const char *key, const char *value)

{

	FILE *file;

	char *sect1, *sect2, *cont1, *cont2, *nextsect;

	char *p;

	int len, type;

	char content[SIZE_LINE];

	char *key0, *value0;

	char *rem1, *rem2, *nextline;



	if (gBuffer == NULL) {

		return 0;

	}


	if (FindSection(section, §1, §2, &cont1, &cont2, &nextsect) == 0)

	{

		//未找到节


		//value无效则返回

		if (value == NULL) 

			return 0;


		//在文件尾部添加

		file = fopen(gFilename, "ab");

		if (file == NULL) 

			return 0;

		fprintf(file, "n[%s]n%s = %sn", section, key, value);

		fclose(file);

		iniFileLoad(gFilename);

		return 1;

	}


	//找到节,则节内查找key

	p = cont1;

	len = (int)(cont2 - cont1);

	while (len > 0) {

		type = GetLine(p, len, content, &rem1, &rem2, &nextline);


		if (LINE_VALUE == type) {

			GetKeyValue(content, &key0, &value0);

			if (StriCmp(key0, key) == 0) {

				//找到key

				file = fopen(gFilename, "wb");

				if (file == NULL) 

					return 0;

				len = (int)(p - gBuffer);

				fwrite(gBuffer, 1, len, file);					//写入key之前部分

				if (value == NULL) {

					//value无效,删除

					len = (int)(nextline - gBuffer);			//整行连同注释一并删除

				} else {

					//value有效,改写

					fprintf(file, "%s = %s", key, value);

					len = (int)(rem1 - gBuffer);				//保留尾部原注释!

				}

				fwrite(gBuffer + len, 1, gBuflen - len, file);	//写入key所在行含注释之后部分

				fclose(file);

				iniFileLoad(gFilename);

				return 1;

			}	

		}


		len -= (int)(nextline - p);

		p = nextline;

	}


	//未找到key


	//value无效则返回

	if (value == NULL) 

		return 0;


	//在文件尾部添加

	file = fopen(gFilename, "wb");

	if (file == NULL) 

		return 0;

	len = (int)(cont2 - gBuffer);

	fwrite(gBuffer, 1, len, file);					//写入key之前部分

	fprintf(file, "%s = %sn", key, value);

	fwrite(gBuffer + len, 1, gBuflen - len, file);	//写入key之后部分

	fclose(file);

	iniFileLoad(gFilename);

	return 1;

}



//设置整数值:base取值10、16、8,分别表示10、16、8进制,缺省为10进制

int iniSetInt(const char *section, const char *key, int value, int base)

{

	char valstr[64];


	switch (base) {

	case 16:

		sprintf(valstr, "0x%x", value);

		return iniSetString(section, key, valstr);

	case 8:

		sprintf(valstr, "0%o", value);

		return iniSetString(section, key, valstr);

	default:	//10

		sprintf(valstr, "%d", value);

		return iniSetString(section, key, valstr);

	}

}


用法举例:

void APP_HookOpenMemory( void )

{

	char *sect;

	char *key;

	char value[256];

	char stadate[10];

	char enddate[10];

	//==================加载配置文件

	const char *file = "config.ini";

	//Hook_Debug_TxData("加载配置...");

	//printf("load config file %snn", file);

	iniFileLoad(file);

	//加载IP地址和端口

	sect = "IpConfig";

	key  = "IP";

	iniGetString(sect, key, IPADDR, sizeof(IPADDR), "notfound!");

	printf("[%11s] %11s = %sn", sect, key, IPADDR);


	key = "PORT";

	PORT = iniGetInt(sect, key, 5035);

	printf("[%11s] %11s = %dn", sect, key, PORT);

	//加载终端编号

	sect = "OthCfg";

	key  = "PosCode";

	iniGetString(sect, key, value, sizeof(value), "notfound!");

	printf("[%11s] %11s = %sn", sect, key, value);

	CurCalc_ASCII_Proc( 2, (U08*)value, strlen(value),gSamAppInfo.PsamTID, 0 );

	//加载密钥状态

	key  = "ComKeyStat";

	OthCfg.ComKeyStat = iniGetInt(sect, key, 0);

	printf("[%11s] %11s = %dn", sect, key, OthCfg.ComKeyStat);

	//加载通信密钥

	key  = "ComKey";

	iniGetString(sect, key, value, sizeof(value), "notfound!");

	printf("[%11s] %11s = %sn", sect, key, value);

	CurCalc_ASCII_Proc( 2, (U08*)value, strlen(value),OthCfg.ComKey, 0 );

	//加载文件信息

	sect = "RecCfg";

	key  = "RecName";

	iniGetString(sect, key, value, sizeof(value), "notfound!");

	strcpy(Rec_Name,value);

	printf("[%11s] %11s = %sn", sect, key, Rec_Name);

	key  = "StaDate";

	iniGetString(sect, key, value, sizeof(value), "notfound!");

	printf("[%11s] %11s = %sn", sect, key, value);

	strcpy(stadate,value);

	key  = "EndDate";

	iniGetString(sect, key, value, sizeof(value), "notfound!");

	printf("[%11s] %11s = %sn", sect, key, value);

	strcpy(enddate,value);


	Get_RecNum(Rec_Name,stadate,enddate);


	iniFileFree();

}

-------------------------------------------------------------------------------------------

成功不是追求别人眼中的最好,而是把自己能做的事情做得最好。

每个人都应该有梦想,这才是生命的意义。

做事情贵在坚持,只有这份坚持,才实践了意义。

处处留心皆学问,爱学习,爱思考。

在这里分享学习,分享感悟,共同进步。

凝聚学习的圈子,思考的圈子。

凝聚学习和思考的圈子。

--------------------------------------------------------------------------------------------