日常知识点之c语言按行读配置文件,及行尾符CRLF导致的问题

本文讲述了开发者在Windows环境中处理配置文件时遇到的换行符问题,通过实例演示了如何解析带有' '的行尾,并修复了printf输出格式问题。重点在于Windows和Unix/Linux环境下的文本处理技巧。

1:知识点总结

Unix每行结尾为"\n",

Windows系统每行结尾是"\r\n"

printf输出时,如果内部字段含有\r,会自动跳转到行首进行后续的输出

printf输出时,有时候一直不打印,是因为printf底层是有缓冲区的,要在终端输出要用换行

2:简单问题描述。

行为:我在做一个读取配置文件并进行解析的简单demo,按行读取,使用=进行分割,对value值进行拼接。
问题:按行读取后,printf打印一直无法理解,出现现象一直如下:

例如:  const char* test="mytest of data.\r";
	   printf("test:[%s][%lu] \n", test, strlen(test));
	实际输出为: ][16] mytest of data.

因为一直没想到行尾描述符的差异,以及printf输出该现象第一次遇到,定位稍久。

3:问题定位。

通过猜测,加日志的的方式进行定位。
最后发现,按行读取文件,=解析后,读取到的字符串比原文件中除了\n还多了一个字符。
想到windows环境下,行尾标志"\r\n"的差异

4:按行读配置文件,查找key值,=进行解析,并拼接的测试demo

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*******************************
1:读配置文件
2:解析配置文件中的所有行,解析出需要的字段
3:对解析出的字段进行拼接打印
********************************/
typedef struct _t_project_ctrol
{
	char target_name[40];
	char major_version[5];
	char sub_version[5];
	char stage_version[5];
}PROJECT_CTROL;

enum PROJECT_CTROL_ENUM
{
	PROJECT_NAME,
	PROJECT_MAJOR_VERSION,
	PROJECT_SUB_VERSION,
	PROJECT_STAGE_VERSION,
	PROJECT_OTHER_ERROR
};

enum PROJECT_CTROL_ENUM parse_para(const char* data)
{
	const char* project_name = "test_project_name";
	const char* major_version = "test_major_version";
	const char* sub_version = "test_sub_version";
	const char* stage_version = "test_stage_version";
	if(strstr(data, project_name) != NULL)
	{
		return PROJECT_NAME;
	}

	if(strstr(data, major_version) != NULL)
	{
		return PROJECT_MAJOR_VERSION;
	}

	if(strstr(data, sub_version) != NULL)
	{
		return PROJECT_SUB_VERSION;
	}

	if(strstr(data, stage_version) != NULL)
	{
		return PROJECT_STAGE_VERSION;
	}
	return PROJECT_OTHER_ERROR;
}

int parse_line(const char* data, PROJECT_CTROL* result_t)
{
	if(data == NULL ||data[0] == '\0')
	{
		return -1;
	}
	//使用=进行切割
	// 实际结果是 data: len:20 ject_name=hxxllo
	// 期望结果是 data:wucg_project_name=hxxllo len:20
	// printf("data:%s len:%lu \n", data,strlen(data)); //因为fgets函数读windows配置文件,行尾是\r\n 

	char * spilt_char;
	spilt_char = strchr(data, '=');
	if(spilt_char == NULL)
	{
		return -1;
	}
	spilt_char++;
	switch(parse_para(data))
	{
		case PROJECT_NAME:
			memcpy(result_t->target_name, spilt_char, strlen(spilt_char));
			break;
		case PROJECT_MAJOR_VERSION:
			memcpy(result_t->major_version, spilt_char, strlen(spilt_char));
			break;
		case PROJECT_SUB_VERSION:
			memcpy(result_t->sub_version, spilt_char, strlen(spilt_char));
			break;
		case PROJECT_STAGE_VERSION:
			memcpy(result_t->stage_version, spilt_char, strlen(spilt_char));
			break;
		default:
			break;
	}
	return 0;
}

int get_config_information(char* proj_version)
{
	FILE *fp;
	const char * filename="hello_config.mk";
	char line[1000]={0};
	fp = fopen(filename, "r");
	if(fp==NULL)
	{
		printf("fopen file error \n");
		return -1;
	}

	PROJECT_CTROL project_verinson_t;
	memset(&project_verinson_t, 0, sizeof(PROJECT_CTROL));
	int line_len = 0;

	while(!feof(fp))
	{
		memset(line, 0, 1000);
		fgets(line,1000,fp); //会影响到printf函数的打印  因为windows和linux换行符导致
		
		line_len = strlen(line); //这里因为行尾终结符号为\r\n
		line[line_len-2] = '\0';
		parse_line(line, &project_verinson_t);
	}
	fclose(fp);

	sprintf(proj_version, "%s-%s.%s.%s", 
			project_verinson_t.target_name, 
			project_verinson_t.major_version,
			project_verinson_t.sub_version,
			project_verinson_t.stage_version);
	return 0;
}

int main()
{
	char version [50];
	memset(version, 0, 50);
	get_config_information(version);
	printf("get project version is [%s] \n", version);
	return 0;
}

/**********************
配置文件:hello_config.mk
    test_project_name=hxxllo
    test_major_version=1
    test_sub_version=0
    test_stage_version=1
输出结果:
	get project version is [hxxllo-1.0.1]
**********************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值