ini配置文件读写实现

头文件:

#pragma once

class OperateIni
{
public:
	OperateIni(void);
	~OperateIni(void);
	
	//获取字符串,不带引号
	static int iniGetString(const char *section, const char *key, const char *defvalue, char *value, int maxlen, const char *filePath);

	//获取整数值
	static int iniGetInt(const char *section, const char *key, int defvalue,const char* filePath);

	//设置字符串:若value为NULL,则删除该key所在行,包括注释
	static int iniSetString(const char *section, const char *key, const char *value, const char* filePath);



	static char *StrStrip(char *s);
	static int StriCmp(const char *s1, const char *s2);
	static int GetLine(char *buf, int buflen, char *content, char **rem1, char **rem2, char **nextline);
	static int FindSection(const char *section, char **sect1, char **sect2, char **cont1, char **cont2, char **nextsect, char* gBuffer, int gBuflen);
	static void GetKeyValue(char *content, char **key, char **value);
	static int iniFileLoad(const char *filename, char* gBuffer, int* gBuflen);
	static int iniGetValue(const char *section, const char *key, const char *defvalue, char *value, int maxlen, char* gBuffer, int gBuflen);

};

源文件:

#include "StdAfx.h"
#include "OperateIni.h"
#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 ;


OperateIni::OperateIni(void)
{
}

OperateIni::~OperateIni(void)
{
}







//去除串首尾空格,原串被改写
char *OperateIni::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) = '\0';

	p1 = s;
	while (*p1 && isspace(*p1))
		p1 ++;
	if (s != p1)
		memmove(s, p1, p2 - p1 + 2);
	return s;
}


//不区分大小写比较字符串
int OperateIni::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)
int OperateIni::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、\r\n、\n\r
	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
//输入:节名称
//输出:成功与否、节名称首、节名称尾、节内容首、节内容尾(含换行)、下一节首(节尾与下一节首间为空行或注释行)
int OperateIni::FindSection(const char *section, char **sect1, char **sect2, char **cont1, char **cont2, char **nextsect, char* gBuffer, int gBuflen)
{
	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;
}


//从一行取键、值
//输入:内容串(将被改写)
//输出:键串、值串
void OperateIni::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 OperateIni::iniFileLoad(const char *filename, char* gBuffer, int* gBuflen)
{
	FILE *file;
	int len;

	if (strlen(filename) == 0)
		return 0;

	file = fopen(filename, "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;
}


//读取值原始串
int OperateIni::iniGetValue(const char *section, const char *key, const char *defvalue, char *value, int maxlen, char* gBuffer, int gBuflen)
{
	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((int)strlen(defvalue), maxlen - 1);
			strncpy(value, defvalue, len);
			value[len] = 0;
		} else {
			value[0] = 0;
		}
	}
	return 0;
}


//获取字符串,不带引号
int OperateIni::iniGetString(const char *section, const char *key, const char *defvalue, char *value, int maxlen, const char *filePath)
{
	int ret;
	int len;

	char buf[10240];
	int fileLen = 0;
	memset(buf, 0, sizeof(buf));
	iniFileLoad(filePath, buf, &fileLen);

	ret = iniGetValue(section, key, defvalue, value, maxlen, buf, fileLen);
	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 OperateIni::iniGetInt(const char *section, const char *key, int defvalue, const char* filePath)
{
	char valstr[64];
	char gBuffer[10240];
	int gBuflen = 0;
	memset(gBuffer, 0, sizeof(gBuffer));
	iniFileLoad(filePath, gBuffer, &gBuflen);

	if (iniGetValue(section, key, "", valstr, sizeof(valstr), gBuffer, gBuflen))
	    return (int)strtol(valstr, NULL, 0);
	return defvalue;
}




//设置字符串:若value为NULL,则删除该key所在行,包括注释
int OperateIni::iniSetString(const char *section, const char *key, const char *value, const char* filePath)
{
	FILE *file;
	char *sect1, *sect2, *cont1, *cont2, *nextsect;
	char *p;
	int len, type;
	char content[SIZE_LINE];
	char *key0, *value0;
	char *rem1, *rem2, *nextline;

	char gBuffer[10240];
	int gBuflen = 0;
	memset(gBuffer, 0, sizeof(gBuffer));
	iniFileLoad(filePath, gBuffer, &gBuflen);

	if (gBuffer == NULL) {
		return 0;
	}

	if (FindSection(section, §1, §2, &cont1, &cont2, &nextsect, gBuffer, gBuflen) == 0)
	{
		//未找到节

		//value无效则返回
		if (value == NULL) 
			return 0;

		//在文件尾部添加
		file = fopen(filePath, "ab");
		if (file == NULL) 
			return 0;
		fprintf(file, "\n[%s]\n%s = %s\n", 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(filePath, "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(filePath, "wb");
	if (file == NULL) 
		return 0;
	len = (int)(cont2 - gBuffer);
	fwrite(gBuffer, 1, len, file);					//写入key之前部分
	fprintf(file, "%s = %s\n", key, value);
	fwrite(gBuffer + len, 1, gBuflen - len, file);	//写入key之后部分
	fclose(file);
	//iniFileLoad(gFilename);
	return 1;
}




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
纯c读写ini配置文件 用c/c++读写ini配置文件有不少第三方的开源库,如iniparser、libini、rwini、UltraLightINIParser等,但都不理想,往往代码较大、功能较弱、 接口使用不方便。尤其在大小写处理、前后空格、各种注释、跨平台换行符支持、带引号字符串处理、无section操作、原格式保持等方面存在问题。 现将本人精心制作的ini读写程序源码奉献给大家,纯c编写,简洁好用。支持windows和linux。 主要特点: 1、支持;和#注释符号,支持行尾注释。 2、支持带引号'或"成对匹配的字符串,提取时自动去引号。引号中可带其它引号或;#注释符。 3、支持无section或空section(名称为空)。 4、支持10、16、8进制数,0x开头为16进制数,0开头为8进制。 5、支持section、key或=号前后带空格。 6、支持\n、\r、\r\n或\n\r换行格式。 7、不区分section、key大小写,但写入时以新串为准,并保持其大小写。 8、新增数据时,若section存在则在该节最后一个有效数据后添加,否则在文件尾部添加。 9、支持指定key所在整行删除,即删除该键值,包括注释。 10、可自动跳过格式错误行,修改时仍然保留。 11、修改时保留原注释:包括整行注释、行尾注释(包括前面空格)。 12、修改时保留原空行。以上三点主要是尽量保留原格式。 不足之处: 1、不支持单key多value(逗号分割),只能一次性提取后自行处理。 2、不支持同名重复section和key。(重复section可视为错误,重复key则可能造成分歧) 3、不能提取所有section或key名称。 使用只需两个文件inirw.h、inirw.c,另有测试程序和工程文件,支持windows和linux。
c ini配置文件读写是一种常见的配置文件读写方式。在C语言中,通常使用文件操作函数来读写ini配置文件。 读取ini文件首先需要打开文件,可以使用fopen函数打开文件,并指定打开方式为"r"(只读方式)。然后逐行读取文件内容,可以使用fgets函数逐行读取。读取到的每一行字符串都可以通过字符串处理函数进行进一步操作,例如使用strtok函数将行字符串分割成键值对。 对于每一行的键值对,可以进一步使用字符串处理函数进行解析。可以使用strchr函数找到等号(=)的位置,将键和值分隔开。然后可以使用strcpy或strncpy函数将键和值分别复制到变量中,并进行相应的后续处理。 写入ini文件也需要打开文件,可以使用fopen函数打开文件,并指定打开方式为"w"(写入方式)。然后可以使用fprintf函数将配置项写入文件。具体的操作是先写入键的字符串,然后写入等号(=),最后写入值的字符串。写入完毕后,可以使用fclose函数关闭文件。 需要注意的是,在读取和写入ini文件时,需要进行错误处理,例如检查文件是否打开成功、是否成功读写、文件关闭时是否出错等。这样可以保证程序的健壮性。 总之,对于C语言来说,ini配置文件读写是一种比较简单和常见的操作,通过使用文件操作函数和字符串处理函数,可以方便地读取和写入ini文件中的配置项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值