c语言直接读写ini配置文件

简介: c语言直接读写ini配置文件

现场好多地方反馈记录全采出来,无法入库。实际上采集部门专门做有一数据分析入库工具,但不是标准的,每个地方都需要采集部门特殊改。


于是想到自己做一工具,模拟车载机通信,把全采出来的数据通过连接采集前置传至采集本地库。但是遇到一问题,参数和配置如何保存?


windows系统中有一种ini配置文件,可以用它来保存配置。高级语言操作ini文件很简单,有现有的库,但c语言,只能自己做一个了。分享下


C直接操作ini文件源码:


**
 * 文件:inirw.h
 * 版本:1.0
 *
 * 说明:ini配置文件读写
 * 1、支持;和#注释符号,支持行尾注释。
 * 2、支持带引号'或"成对匹配的字符串,提取时自动去引号。引号中可带其它引号或;#注释符。
 * 3、支持无section或空section(名称为空)。
 * 4、支持10、16、8进制数,0x开头为16进制数,0开头为8进制。
 * 5、支持section、key或=号前后带空格。
 * 6、支持n、r、rn或nr换行格式。
 * 7、不区分section、key大小写,但写入时以新串为准,并保持其大小写。
 * 8、新增数据时,若section存在则在该节最后一个有效数据后添加,否则在文件尾部添加。
 * 9、支持指定key所在整行删除,即删除该键值,包括注释。
 * 10、可自动跳过格式错误行,修改时仍然保留。
 * 11、修改时保留原注释:包括整行注释、行尾注释(包括前面空格)。
 * 12、修改时保留原空行。以上三点主要是尽量保留原格式。
 */
inirw.h头文件:
#ifndef _INI_RW_H_
#define _INI_RW_H_
#ifdef __cplusplus
extern "C" {
#endif
//加载ini文件至内存
int iniFileLoad(const char *filename);
//释放ini文件所占资源
void iniFileFree();
//获取字符串,不带引号
int iniGetString(const char *section, const char *key, char *value, int size, const char *defvalue);
//获取整数值
int iniGetInt(const char *section, const char *key, int defvalue);
//获取浮点数
double iniGetDouble(const char *section, const char *key, double defvalue);
//设置字符串:若value为NULL,则删除该key所在行,包括注释
int iniSetString(const char *section, const char *key, const char *value);
//设置整数值:base取值10、16、8,分别表示10、16、8进制,缺省为10进制
int iniSetInt(const char *section, const char *key, int value, int base);
#ifdef __cplusplus
}
#endif
#endif
inirw.c文件:
#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 ;
static char gFilename[SIZE_FILENAME];
static char *gBuffer;
static int gBuflen;
//去除串首尾空格,原串被改写
static char *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) = '';
  p1 = s;
  while (*p1 && isspace(*p1))
    p1 ++;
  if (s != p1)
    memmove(s, p1, p2 - p1 + 2);
  return s;
}
//不区分大小写比较字符串
static int 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)
static int 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、rn、nr
  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
//输入:节名称
//输出:成功与否、节名称首、节名称尾、节内容首、节内容尾(含换行)、下一节首(节尾与下一节首间为空行或注释行)
static int FindSection(const char *section, char **sect1, char **sect2, char **cont1, char **cont2, char **nextsect)
{
  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;
}
//从一行取键、值
//输入:内容串(将被改写)
//输出:键串、值串
static void 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 iniFileLoad(const char *filename)
{
  FILE *file;
  int len;
  iniFileFree();
  if (strlen(filename) >= sizeof(gFilename))
    return 0;
  strcpy(gFilename, filename);
  file = fopen(gFilename, "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;
}
//读取值原始串
static int iniGetValue(const char *section, const char *key, char *value, int maxlen, const char *defvalue)
{
  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(strlen(defvalue), maxlen - 1);
      strncpy(value, defvalue, len);
      value[len] = 0;
    } else {
      value[0] = 0;
    }
  }
  return 0;
}
//获取字符串,不带引号
int iniGetString(const char *section, const char *key, char *value, int maxlen, const char *defvalue)
{
  int ret;
  int len;
  ret = iniGetValue(section, key, value, maxlen, defvalue);
  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 iniGetInt(const char *section, const char *key, int defvalue)
{
  char valstr[64];
  if (iniGetValue(section, key, valstr, sizeof(valstr), NULL))
      return (int)strtol(valstr, NULL, 0);
  return defvalue;
}
//获取浮点数
double iniGetDouble(const char *section, const char *key, double defvalue)
{
  char valstr[64];
  if (iniGetValue(section, key, valstr, sizeof(valstr), NULL))
      return (int)atof(valstr);
  return defvalue;
}
//设置字符串:若value为NULL,则删除该key所在行,包括注释
int iniSetString(const char *section, const char *key, const char *value)
{
  FILE *file;
  char *sect1, *sect2, *cont1, *cont2, *nextsect;
  char *p;
  int len, type;
  char content[SIZE_LINE];
  char *key0, *value0;
  char *rem1, *rem2, *nextline;
  if (gBuffer == NULL) {
    return 0;
  }
  if (FindSection(section, §1, §2, &cont1, &cont2, &nextsect) == 0)
  {
    //未找到节
    //value无效则返回
    if (value == NULL) 
      return 0;
    //在文件尾部添加
    file = fopen(gFilename, "ab");
    if (file == NULL) 
      return 0;
    fprintf(file, "n[%s]n%s = %sn", 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(gFilename, "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(gFilename, "wb");
  if (file == NULL) 
    return 0;
  len = (int)(cont2 - gBuffer);
  fwrite(gBuffer, 1, len, file);          //写入key之前部分
  fprintf(file, "%s = %sn", key, value);
  fwrite(gBuffer + len, 1, gBuflen - len, file);  //写入key之后部分
  fclose(file);
  iniFileLoad(gFilename);
  return 1;
}
//设置整数值:base取值10、16、8,分别表示10、16、8进制,缺省为10进制
int iniSetInt(const char *section, const char *key, int value, int base)
{
  char valstr[64];
  switch (base) {
  case 16:
    sprintf(valstr, "0x%x", value);
    return iniSetString(section, key, valstr);
  case 8:
    sprintf(valstr, "0%o", value);
    return iniSetString(section, key, valstr);
  default:  //10
    sprintf(valstr, "%d", value);
    return iniSetString(section, key, valstr);
  }
}
用法举例:
void APP_HookOpenMemory( void )
{
  char *sect;
  char *key;
  char value[256];
  char stadate[10];
  char enddate[10];
  //==================加载配置文件
  const char *file = "config.ini";
  //Hook_Debug_TxData("加载配置...");
  //printf("load config file %snn", file);
  iniFileLoad(file);
  //加载IP地址和端口
  sect = "IpConfig";
  key  = "IP";
  iniGetString(sect, key, IPADDR, sizeof(IPADDR), "notfound!");
  printf("[%11s] %11s = %sn", sect, key, IPADDR);
  key = "PORT";
  PORT = iniGetInt(sect, key, 5035);
  printf("[%11s] %11s = %dn", sect, key, PORT);
  //加载终端编号
  sect = "OthCfg";
  key  = "PosCode";
  iniGetString(sect, key, value, sizeof(value), "notfound!");
  printf("[%11s] %11s = %sn", sect, key, value);
  CurCalc_ASCII_Proc( 2, (U08*)value, strlen(value),gSamAppInfo.PsamTID, 0 );
  //加载密钥状态
  key  = "ComKeyStat";
  OthCfg.ComKeyStat = iniGetInt(sect, key, 0);
  printf("[%11s] %11s = %dn", sect, key, OthCfg.ComKeyStat);
  //加载通信密钥
  key  = "ComKey";
  iniGetString(sect, key, value, sizeof(value), "notfound!");
  printf("[%11s] %11s = %sn", sect, key, value);
  CurCalc_ASCII_Proc( 2, (U08*)value, strlen(value),OthCfg.ComKey, 0 );
  //加载文件信息
  sect = "RecCfg";
  key  = "RecName";
  iniGetString(sect, key, value, sizeof(value), "notfound!");
  strcpy(Rec_Name,value);
  printf("[%11s] %11s = %sn", sect, key, Rec_Name);
  key  = "StaDate";
  iniGetString(sect, key, value, sizeof(value), "notfound!");
  printf("[%11s] %11s = %sn", sect, key, value);
  strcpy(stadate,value);
  key  = "EndDate";
  iniGetString(sect, key, value, sizeof(value), "notfound!");
  printf("[%11s] %11s = %sn", sect, key, value);
  strcpy(enddate,value);
  Get_RecNum(Rec_Name,stadate,enddate);
  iniFileFree();
}
相关文章
C4.
|
6月前
|
存储 程序员 数据库
C语言顺序读写数据文件
C语言顺序读写数据文件
C4.
70 0
|
6月前
|
C语言
C语言-读写操作
C语言-读写操作
50 0
|
6月前
|
移动开发 Unix C语言
日常知识点之c语言按行读配置文件,及行尾符CRLF导致的问题
日常知识点之c语言按行读配置文件,及行尾符CRLF导致的问题
92 0
|
存储 Linux C语言
24 C语言 - 文件读写
24 C语言 - 文件读写
60 0
|
C语言 内存技术
C语言—指针读写
主要介绍了如何利用指针实现读写操作。
111 0
|
5月前
|
存储 C语言
C语言文件读写详解
C语言文件读写详解
|
5月前
|
C语言 Windows
【C语言】:文件读写相关函数介绍
【C语言】:文件读写相关函数介绍
39 0
|
5月前
|
Linux API C语言
C语言读写BMP文件-EasyBmp【 linux 平台】
**EasyBmp** 是一个49KB的轻量级C++图像处理库,专注于BMP格式,提供简单易用的API。它的特点是小巧、开源、易于理解和高度定制。通过示例代码展示了如何轻松读取、缩放和保存BMP图像。适合需要高效处理BMP图像的开发者。
|
5月前
|
C语言
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
43 0
|
5月前
|
C语言
C语言进阶——文件的读写(文件使用方式、文件的顺序读写、常用函数、fprintf、fscanf)
C语言进阶——文件的读写(文件使用方式、文件的顺序读写、常用函数、fprintf、fscanf)
39 0