c++读取配置文件

在实际开发中,程序读取配置文件以加载数据非常常见,如何安全高效地读取文件比较重要。本文代码来自于《c++新经典》。

 假设有一个txt格式的文件,里面记录了花里胡哨的内容,需要把这些内容一字不差地读取到程序中,应该如何用c++实现?

书中的代码如下:

#include <iostream>
using namespace std;
int main()
{
	//打开文件
	FILE* fp = nullptr;
	errno_t err;
	err = fopen_s(&fp, "config.txt", "r");
	if (!fp) {
		cout << "can not open file!" << endl;
	}
	//打开文件成功
	else {
		//定义存储每行字符串的数组
		char linebuff[1024];
		//没读到文件尾就一直执行
		while (!feof(fp))
		{
			linebuff[0] = 0;//给第一位置零
			//fgets函数功能为从指定的流中读取数据,每次读取一行。其原型为:char *fgets(char *str, int n, FILE *stream);
			//从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止
			if (fgets(linebuff, sizeof(linebuff) - 1, fp) == nullptr)//如果读到文件尾或者没读到字符,跳出本次循环
				continue;
			if (linebuff[0] == '\0') {//如果数组第一位是零,说明没读到内容,则跳出本次循环
				continue;
			}
		lblprocstring:
			if (strlen(linebuff) > 0) {//如果行尾是换行(0X0A,10)或者换行(0X0D,13)就都截掉
				if (linebuff[strlen(linebuff) - 1] == 10 || linebuff[strlen(linebuff) - 1] == 13) {
					linebuff[strlen(linebuff) - 1] = 0;//截掉,注意strlen不计算句尾的0,sizeof会计算
					goto lblprocstring;
				}
			}
			if (strlen(linebuff) <= 0)//如果是个空行,跳出本次循环
				continue;
			printf("%s\n", linebuff);//打印一行
		}
		fclose(fp);
	}
	return 0;
}

结果如下图所示,已经完整地将配置文件的内容打印出来了。

 代码使用一个字符数组记录每行内容,为防止读取失败,代码中通过第一位清零并查询的方式检查:

            linebuff[0] = 0;//给第一位置零
			......
			if (linebuff[0] == '\0') {//如果数组第一位是零,说明没读到内容,则跳出本次循环
				continue;
			}

如果不需要代码非常严谨,可以将以上的内容从代码中删除。

读取一行文本的核心实现是以下代码:

            //fgets函数功能为从指定的流中读取数据,每次读取一行。其原型为:char *fgets(char *str, int n, FILE *stream);
			//从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止
			if (fgets(linebuff, sizeof(linebuff) - 1, fp) == nullptr)//如果读到文件尾或者没读到字符,跳出本次循环
				continue;

fgets函数读取到内容后,会返回文件流指针fp。

fgets读取 (n-1) 个字符时,或者读取错误时,或者到达文件末尾时,会返回nullptr。在这个情况我们需要考虑该如何处理。

1.如果读取到了最大字符数量,但是仍旧没有读到换行符,说明该行的字符长度超过了数组设置的长度:这种情况下会返回一个不完整的行,并且在下一次会继续在该行进行字符读取。按照书中的设计思路,这种情况不应该出现,配置文件每行的最长长度应该有个明确的上限,该上限决定了字符数组的长度。

2.读取错误:这种情况下没别的可以做,应该采用continue跳过该次循环,进行重复读取 。

3.到达文件尾:这种情况下需要与情况2进行区分,因此循环应使用feof(fp)作为循环的判断依据,通过feof而不是fgets来判断文件是否读取完毕,既然这个任务交给feof去做了,那么这里依然采用continue跳过该次循环即可。

数组读取完数据之后需要对句尾进行裁剪,把回车符号都去掉:

            lblprocstring:
			if (strlen(linebuff) > 0) {//如果行尾是换行(0X0A,10)或者换行(0X0D,13)就都截掉
				if (linebuff[strlen(linebuff) - 1] == 10 || linebuff[strlen(linebuff) - 1] == 13) {
					linebuff[strlen(linebuff) - 1] = 0;//截掉,注意strlen不计算句尾的0,sizeof会计算
					goto lblprocstring;
				}
			}
			if (strlen(linebuff) <= 0)//如果是个空行,跳出本次循环
				continue;
			printf("%s\n", linebuff);//打印一行

这里采用了一个goto循环,在循环中不断地判断数组内数据的尾部是不是回车符或者换行符,若是的话便对该符号进行清零操作。注意这里使用strlen()-1来判断数据末尾的位置,这是因为strlen函数是自动无视掉字符串末尾的‘/0’的,而sizeof并不会,因此在这种末尾清零操作中必须使用strlen。

由于不习惯使用goto循环,我改成了while循环:

            while (strlen(linebuff)>0)
			{
				if (linebuff[strlen(linebuff) - 1] == 10 || linebuff[strlen(linebuff - 1)] == 13) {
					linebuff[strlen(linebuff) - 1] = 0;
				}
				else {
					break;
				}
			}

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值