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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 日常知识点之c语言按行读配置文件,及行尾符CRLF导致的问题

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]
**********************/
目录
相关文章
|
1月前
|
C语言
C语言学习笔记-知识点总结上
C语言学习笔记-知识点总结上
76 1
|
6月前
|
编译器 C语言
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。(下)
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。
42 0
|
4月前
|
存储 编译器 C语言
|
5月前
|
编译器 C语言
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)二
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)二
49 3
|
5月前
|
存储 编译器 C语言
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)一
C语言学习记录——操作符详解知识点选记(算术操作符、单目操作符、移位操作符、关系操作符、逻辑操作符、条件操作符......)一
40 1
|
4月前
|
前端开发 C语言
C语言08----注释扩展知识点,注释快捷键:ctrl+k,ctrl + C,取消快捷键 ctrl + K,ctrl + U
C语言08----注释扩展知识点,注释快捷键:ctrl+k,ctrl + C,取消快捷键 ctrl + K,ctrl + U
|
5月前
|
C语言
C语言----关于二维数组传参的本质相关的知识点(数组指针、指针数组)
C语言----关于二维数组传参的本质相关的知识点(数组指针、指针数组)
|
6月前
|
存储 程序员 编译器
【初阶】C语言指针详解——指针必备的7大知识点
【初阶】C语言指针详解——指针必备的7大知识点
|
6月前
|
存储 C语言
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。(中)
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。
37 0
|
6月前
|
存储 C语言 C++
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。(上)
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。
27 0