使用c语言实现INI文件的读写

INI文件是Windows上独有的一种存储结构,这只是Windows下发明的存储结构,也有很多类似的,比如xml!

就说一下TXT文本

是按行读取,这就是它的格式!

而xml是类似二叉树的带层次结构的存储方式

INI则是以键值的方式将数据对应起来,类似数据库一样!

在Windows上我们可以使用一些自带API实现对INI文件的读取写入,但是在其它系统平台上就不可以了,这里是博主在开发跨平台SDT工具包时,写的一款对INI文件操作的函数

在开始之前我们需要编写一些辅助函数,因为这些存储结构,都是对字符进行处理,我们先读入内存,然后开始字符流处理,这里值得注意的是!

 所以需要编写一些CharString处理字符类,这里是从CharString库里copy出来的,这个库是我开源的,你可以在我的博客SDT分类里找到这个库的介绍以及源码!

//获取文本所在行
int GetStrTxTIndx(char* m_str,const char* Str){
	if (m_str == NULL || Str == NULL){
		return 0;
	}
	int StrSize = strlen(Str);
	if (StrSize <= 0){
		return 0;
	}
	int Str_m_str = strlen(m_str);
	int m_str_index = 0;/*二次循环坐标*/
	int y = 0;
	for (int i = 0; i <= Str_m_str - 1; i++/*加一是因为i从0开始,下方循环是size+1是为了将坐标移动到下个字符*/){
		y = 0;
		m_str_index = i;
		for (int j = 0; j <= StrSize - 1; ++j, ++m_str_index){
			if (Str[j] == m_str[m_str_index]){
				y += 1;
			}
			if (y == StrSize){
				return i + 1;
			}
			if (Str[j] != m_str[m_str_index]){
				break;

			}
		}
	}
	return 0;
}
//获取一行文本
char* GetLineTxT(char* m_str,int LineIndex = 1) {
	if (LineIndex == 0){
		return 0;
	}
	if (m_str == NULL) {
		return 0;
	}
	int l = 0;
	char *yun = NULL;
	int j = 0;
	int u = 0;
	for (int i = 0; i <= strlen(m_str) + 1/*包含\0*/; ++i) {
		if (m_str[i] == '\n') {
			++l;
			if (l != LineIndex)
				u = i + 1;//+1跳过\n 这里递增1后面已经忽略0因为已经不是第一行坐标
		}
		if (l == LineIndex) {
			//判断此行多长用于分配内存
			for (j = u;; ++j) {
				if (m_str[j] == '\n' || m_str[j] == '\0') {
					int size = 0;
					if (u == 0){//防止从0下标导致计算实际长度少1,因为额外的1要用来\0
						size = j + 1;	//+1是因为分配内存不是从0做下标所以需要判断是否为0
					}
					else{
						size = j;
					}
					yun = (char*)malloc(size + 1);	//多分配额外字节,\0
					memset(yun, 0, size + 1);
					break;
				}
			}
			int in = 0;
			for (int n = u; n <= j; ++n, ++in) {
				yun[in] = m_str[n];
			}
			return yun;
		}
	}
}
//获取文本多少行
int GetLineNum(char* m_str){
	if (m_str == NULL){
		return 0;
	}
	int Size = 0;
	for (int i = 0; i <= strlen(m_str)-1; ++i){
		if (m_str[i] == '\n'){
			++Size;
		}
		if (m_str[i] == '\0'){
			if (m_str[i - 1] != '\n'){
				Size++;
			}
			return Size;
		}
	}
	return Size;
}
//判断文本是否存在
bool JumpTxTExits(char* m_str,char *Str){
	if (GetStrTxTIndx(m_str,Str) == 0){
		return false;
	}
	return true;
}
//判断文本在第几行
int GetTxTLineNum(char* m_str,char *Str){
	if (Str == NULL || m_str == NULL){
		return NULL;
	}
	char *str1 = NULL;
	int i = 1;
	int u = GetLineNum(m_str);
	while (1){//查找这个文本格式在第几行里
		str1 = GetLineTxT(m_str,i);
		if (str1 == NULL){
			return NULL;
		}
		if (JumpTxTExits(str1, Str) == true){
			break;
		}
		if (i > u){
			return 0;
		}
		++i;
	}
	return i;
}

 

INI读取:

//ini
char* iniGet(char *FileName, char* Primary_Key, char* Key,bool Speck = true){
	//判断是否为空
	if (Primary_Key == NULL || Key == NULL||FileName == NULL){
		return NULL;
	}
	//格式合成
	char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3);	//[]\0
	memset(FormatStr, 0, strlen(Primary_Key) + 3);
	sprintf(FormatStr, "[%s]", Primary_Key); 
	//读入文件
	FILE *fp = fopen(FileName, "r");
	if (fp == NULL){
		return NULL;
	}
	fseek(fp, 0L, SEEK_END);
	signed long long int size = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	char *txt = (char*)malloc(size + 1);
	memset(txt, 0, size+1);
	fread(txt, size, 1, fp);
	fclose(fp);
	//获取主键值的位置
	int y = GetStrTxTIndx(txt, FormatStr);
	if (y == 0){
		return NULL;
	}
	//循环读取当前键值下的所有值,除遇得下一个键值
	for (int i = y; i <= size-1; ++i){
		if (txt[i] == '\n'){
			for (int j = i; j <= size - 1; ++j){
				if (txt[j] == '['){	//找到了第二个键值
					for (int h = j; h <= size - 1; ++h){
						txt[h] = '\0';
					}
					goto t;	//读取完成后不要继续读取了,直接跳入下一个处理环境,因为我们已经得到当前主键值下的所有内容了
				}
			}
		}
	}
t:
	//判断文本在第几行
	int Lin = GetTxTLineNum(txt, Key);
	if (Lin == 0){
		return NULL;
	}
	//获取所在行文本
	char* st = GetLineTxT(txt, Lin);
	char* stcopy = (char*)malloc(strlen(st) + 1);
	memset(stcopy, 0, strlen(st) + 1);
	strcpy(stcopy, st);
	free(st);
	st = NULL;
	int yunsi = 0;
	//开始处理
	for (int i = 0; i <= strlen(stcopy) - 1; ++i){
		if (stcopy[i] == '='){
			if (Speck){
				if (stcopy[i + 1] == ' '){	//忽略开头空格
					i = i + 1;
					for (; i <= strlen(stcopy) - 1; ++i){
						if (stcopy[i] != ' ')break;

					}
					i = i - 1;
				}
			}
			for (int j = i + 1; j<=strlen(stcopy)-1; ++j){
				++yunsi;
			}
			char* data = (char*)malloc(yunsi + 1);
			if (data == NULL){
				return NULL;
			}
			memset(data, 0, yunsi + 1);
			int hk = 0;
			for (int j = i + 1; j <= strlen(stcopy) - 1; ++j){
				if (stcopy[j] == '\n'){//如果遇到文件尾一样退出
					return data;
				}
				data[hk++] = stcopy[j];
			}
			return data;
		}
	}
	return 0;


}

示列:

ini:

[key1]
Test = test文本
test=这里是不忽略空格的文本
[key2]
Test=test

代码:

iniGet("file.txt","key1","Test");

输出

test文本

//ini写入

//ini
int iniSet(char *FileName, char* Primary_Key, char* Key, char* Data,bool Speck = true){
	if (Primary_Key == NULL || Key == NULL || FileName == NULL){
		return NULL;
	}
	char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3);	//[]\0
	memset(FormatStr, 0, strlen(Primary_Key) + 3);
	sprintf(FormatStr, "[%s]", Primary_Key);
	FILE *fp = fopen(FileName, "r");
	char* flun = NULL;	//用于保存后数据
	if (fp == NULL){
		return NULL;
	}
	fseek(fp, 0L, SEEK_END);
	signed long long int size = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	char *txt = (char*)malloc(size + 1);
	memset(txt, 0, size + 1);
	flun = (char*)malloc(size + 1);
	memset(flun, 0, size + 1);
	char* jnmhand = (char*)malloc(size + 1+strlen(Data));	//保存头
	memset(jnmhand, 0, size + 1 + strlen(Data));
	fread(txt, size, 1, fp);
	int y = GetStrTxTIndx(txt, FormatStr);
	if (y == 0){
		return NULL;
	}
	int yi = 0;
	if (y != 1){
		for (int i = 0; i <= y - 1; ++i){
			jnmhand[i] = txt[i];
		}
	}
	for (int i = y; i <= size - 1; ++i){
		flun[yi++] = txt[i-1];
		if (txt[i] == '\n'){
			for (int j = i; j <= size - 1; ++j){
				flun[yi++] = txt[j];
				if (txt[j] == '['){	//找到了第二个键值
					for (int h = j; h <= size - 1; ++h){
						//flun[yi++] = txt[h];
						txt[h] = '\0';
					}
					goto t;
				}
			}
		}
	}
t:
	int Lin = GetTxTLineNum(flun, Key);
	if (Lin == 0){
		return NULL;
	}
	char* setdata = (char*)malloc(size + strlen(Data) + 1);
	memset(setdata, 0,size + strlen(Data) + 1);
	int nn = 0;
	int gh = 0;
	bool kj = false;	//防止修改数据时再次遇到=
	for (int i = 0; i <= strlen(flun) - 1; ++i){
		if (flun[i] == '\n'){
			++nn;
		}
		if (nn == Lin - 1){	//代表已经到要修改数据行的头,因为\n在尾
			++nn;
			for (int j = i; j <= strlen(flun) - 1; ++j){	//寻找=
				setdata[gh++] = flun[j];
				if (kj == false){
					//kj = true;
					if (flun[j] == '='){
						//寻找有效数据
						if (Speck){
							j = j + 1;
							for (; j <= strlen(flun); ++j){	//寻找有效数据
								if (flun[j] != ' '){
									break;
								}
							}
							j = j - 1;
							i = j;
						}
						int n = 0;
						for (; n <= strlen(Data) - 1; ++n){
							setdata[gh++] = Data[n];
						}
						for (;;){
							++i;
							if (flun[i] == '\n' || flun[i] == '\0'){
								break;
							}
						}
						
						//i = i + n;
						break;
					}
				}
			}
		}
		setdata[gh++] = flun[i];
		
	}
	strcat(jnmhand, setdata);
	//内存释放
	free(txt);
	free(setdata);
	//数据写入
	fp = fopen(FileName, "w");
	if (fp == NULL){
		return 0;
	}
	fwrite(jnmhand, strlen(jnmhand), 1, fp);
	fclose(fp);
	return 0;
}

用法

iniSet("C:\\Users\\ZZH\\Desktop\\test.ini", "uu", "kk"," k");

完整代码:

#include 
#include 
#include 
//获取文本所在行
int GetStrTxTIndx(char* m_str,const char* Str){
	if (m_str == NULL || Str == NULL){
		return 0;
	}
	int StrSize = strlen(Str);
	if (StrSize <= 0){
		return 0;
	}
	int Str_m_str = strlen(m_str);
	int m_str_index = 0;/*二次循环坐标*/
	int y = 0;
	for (int i = 0; i <= Str_m_str - 1; i++/*加一是因为i从0开始,下方循环是size+1是为了将坐标移动到下个字符*/){
		y = 0;
		m_str_index = i;
		for (int j = 0; j <= StrSize - 1; ++j, ++m_str_index){
			if (Str[j] == m_str[m_str_index]){
				y += 1;
			}
			if (y == StrSize){
				return i + 1;
			}
			if (Str[j] != m_str[m_str_index]){
				break;

			}
		}
	}
	return 0;
}
//获取一行文本
char* GetLineTxT(char* m_str,int LineIndex = 1) {
	if (LineIndex == 0){
		return 0;
	}
	if (m_str == NULL) {
		return 0;
	}
	int l = 0;
	char *yun = NULL;
	int j = 0;
	int u = 0;
	for (int i = 0; i <= strlen(m_str) + 1/*包含\0*/; ++i) {
		if (m_str[i] == '\n') {
			++l;
			if (l != LineIndex)
				u = i + 1;//+1跳过\n 这里递增1后面已经忽略0因为已经不是第一行坐标
		}
		if (l == LineIndex) {
			//判断此行多长用于分配内存
			for (j = u;; ++j) {
				if (m_str[j] == '\n' || m_str[j] == '\0') {
					int size = 0;
					if (u == 0){//防止从0下标导致计算实际长度少1,因为额外的1要用来\0
						size = j + 1;	//+1是因为分配内存不是从0做下标所以需要判断是否为0
					}
					else{
						size = j;
					}
					yun = (char*)malloc(size + 1);	//多分配额外字节,\0
					memset(yun, 0, size + 1);
					break;
				}
			}
			int in = 0;
			for (int n = u; n <= j; ++n, ++in) {
				yun[in] = m_str[n];
			}
			return yun;
		}
	}
}
//获取文本多少行
int GetLineNum(char* m_str){
	if (m_str == NULL){
		return 0;
	}
	int Size = 0;
	for (int i = 0; i <= strlen(m_str)-1; ++i){
		if (m_str[i] == '\n'){
			++Size;
		}
		if (m_str[i] == '\0'){
			if (m_str[i - 1] != '\n'){
				Size++;
			}
			return Size;
		}
	}
	return Size;
}
//判断文本是否存在
bool JumpTxTExits(char* m_str,char *Str){
	if (GetStrTxTIndx(m_str,Str) == 0){
		return false;
	}
	return true;
}
//判断文本在第几行
int GetTxTLineNum(char* m_str,char *Str){
	if (Str == NULL || m_str == NULL){
		return NULL;
	}
	char *str1 = NULL;
	int i = 1;
	int u = GetLineNum(m_str);
	while (1){//查找这个文本格式在第几行里
		str1 = GetLineTxT(m_str,i);
		if (str1 == NULL){
			return NULL;
		}
		if (JumpTxTExits(str1, Str) == true){
			break;
		}
		if (i > u){
			return 0;
		}
		++i;
	}
	return i;
}
//ini
char* iniGet(char *FileName, char* Primary_Key, char* Key,bool Speck = true){
	//判断是否为空
	if (Primary_Key == NULL || Key == NULL||FileName == NULL){
		return NULL;
	}
	//格式合成
	char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3);	//[]\0
	memset(FormatStr, 0, strlen(Primary_Key) + 3);
	sprintf(FormatStr, "[%s]", Primary_Key); 
	//读入文件
	FILE *fp = fopen(FileName, "r");
	if (fp == NULL){
		return NULL;
	}
	fseek(fp, 0L, SEEK_END);
	signed long long int size = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	char *txt = (char*)malloc(size + 1);
	memset(txt, 0, size+1);
	fread(txt, size, 1, fp);
	fclose(fp);
	//获取主键值的位置
	int y = GetStrTxTIndx(txt, FormatStr);
	if (y == 0){
		return NULL;
	}
	//循环读取当前键值下的所有值,除遇得下一个键值
	for (int i = y; i <= size-1; ++i){
		if (txt[i] == '\n'){
			for (int j = i; j <= size - 1; ++j){
				if (txt[j] == '['){	//找到了第二个键值
					for (int h = j; h <= size - 1; ++h){
						txt[h] = '\0';
					}
					goto t;	//读取完成后不要继续读取了,直接跳入下一个处理环境,因为我们已经得到当前主键值下的所有内容了
				}
			}
		}
	}
t:
	//判断文本在第几行
	int Lin = GetTxTLineNum(txt, Key);
	if (Lin == 0){
		return NULL;
	}
	//获取所在行文本
	char* st = GetLineTxT(txt, Lin);
	char* stcopy = (char*)malloc(strlen(st) + 1);
	memset(stcopy, 0, strlen(st) + 1);
	strcpy(stcopy, st);
	free(st);
	st = NULL;
	int yunsi = 0;
	//开始处理
	for (int i = 0; i <= strlen(stcopy) - 1; ++i){
		if (stcopy[i] == '='){
			if (Speck){
				if (stcopy[i + 1] == ' '){	//忽略开头空格
					i = i + 1;
					for (; i <= strlen(stcopy) - 1; ++i){
						if (stcopy[i] != ' ')break;

					}
					i = i - 1;
				}
			}
			for (int j = i + 1; j<=strlen(stcopy)-1; ++j){
				++yunsi;
			}
			char* data = (char*)malloc(yunsi + 1);
			if (data == NULL){
				return NULL;
			}
			memset(data, 0, yunsi + 1);
			int hk = 0;
			for (int j = i + 1; j <= strlen(stcopy) - 1; ++j){
				if (stcopy[j] == '\n'){//如果遇到文件尾一样退出
					return data;
				}
				data[hk++] = stcopy[j];
			}
			return data;
		}
	}
	return 0;


}
//ini
int iniSet(char *FileName, char* Primary_Key, char* Key, char* Data,bool Speck = true){
	if (Primary_Key == NULL || Key == NULL || FileName == NULL){
		return NULL;
	}
	char *FormatStr = (char*)malloc(strlen(Primary_Key) + 3);	//[]\0
	memset(FormatStr, 0, strlen(Primary_Key) + 3);
	sprintf(FormatStr, "[%s]", Primary_Key);
	FILE *fp = fopen(FileName, "r");
	char* flun = NULL;	//用于保存后数据
	if (fp == NULL){
		return NULL;
	}
	fseek(fp, 0L, SEEK_END);
	signed long long int size = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	char *txt = (char*)malloc(size + 1);
	memset(txt, 0, size + 1);
	flun = (char*)malloc(size + 1);
	memset(flun, 0, size + 1);
	char* jnmhand = (char*)malloc(size + 1+strlen(Data));	//保存头
	memset(jnmhand, 0, size + 1 + strlen(Data));
	fread(txt, size, 1, fp);
	int y = GetStrTxTIndx(txt, FormatStr);
	if (y == 0){
		return NULL;
	}
	int yi = 0;
	if (y != 1){
		for (int i = 0; i <= y - 1; ++i){
			jnmhand[i] = txt[i];
		}
	}
	for (int i = y; i <= size - 1; ++i){
		flun[yi++] = txt[i-1];
		if (txt[i] == '\n'){
			for (int j = i; j <= size - 1; ++j){
				flun[yi++] = txt[j];
				if (txt[j] == '['){	//找到了第二个键值
					for (int h = j; h <= size - 1; ++h){
						//flun[yi++] = txt[h];
						txt[h] = '\0';
					}
					goto t;
				}
			}
		}
	}
t:
	int Lin = GetTxTLineNum(flun, Key);
	if (Lin == 0){
		return NULL;
	}
	char* setdata = (char*)malloc(size + strlen(Data) + 1);
	memset(setdata, 0,size + strlen(Data) + 1);
	int nn = 0;
	int gh = 0;
	bool kj = false;	//防止修改数据时再次遇到=
	for (int i = 0; i <= strlen(flun) - 1; ++i){
		if (flun[i] == '\n'){
			++nn;
		}
		if (nn == Lin - 1){	//代表已经到要修改数据行的头,因为\n在尾
			++nn;
			for (int j = i; j <= strlen(flun) - 1; ++j){	//寻找=
				setdata[gh++] = flun[j];
				if (kj == false){
					//kj = true;
					if (flun[j] == '='){
						//寻找有效数据
						if (Speck){
							j = j + 1;
							for (; j <= strlen(flun); ++j){	//寻找有效数据
								if (flun[j] != ' '){
									break;
								}
							}
							j = j - 1;
							i = j;
						}
						int n = 0;
						for (; n <= strlen(Data) - 1; ++n){
							setdata[gh++] = Data[n];
						}
						for (;;){
							++i;
							if (flun[i] == '\n' || flun[i] == '\0'){
								break;
							}
						}
						
						//i = i + n;
						break;
					}
				}
			}
		}
		setdata[gh++] = flun[i];
		
	}
	strcat(jnmhand, setdata);
	//内存释放
	free(txt);
	free(setdata);
	//数据写入
	fp = fopen(FileName, "w");
	if (fp == NULL){
		return 0;
	}
	fwrite(jnmhand, strlen(jnmhand), 1, fp);
	fclose(fp);
	return 0;
}
int main()
{
	 iniSet("C:\\Users\\ZZH\\Desktop\\test.ini", "uu", "kk"," k");
	
	getchar();
	return 0;
}

 

你可能感兴趣的:(C/C++,ini)