我是靠谱客的博主 笨笨百褶裙,最近开发中收集的这篇文章主要介绍一个用标准C写的ini文件操作程序,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ini文件的基本格式如下:

   1: [Section1]
   2: Name1=Value1
   3: Name2=Value2
   4:  
   5: [Section2]
   6: Name1=Value1
   7: Name2=Value2

ini文件由section组成,每个section内可以定义若干个属性,以及他们的值。

ini文件算是一种比较简单的信息管理方式了,内容简单,格式简单,使用起来也简单。而且内容全部是ASCII,直观。

在很多场合都可能会用到ini文件,比如,希望我们写的程序可以让用户做一些细微的配置的时候,或者,希望程序可以具备保存设置的能力的时候。

下面给出一个用双向链表来操作ini的代码实现方式。

我用了三个结构体来描述一个ini文件:

   1: typedef struct ini_item_t {
   2:     struct ini_item_t *prev;
   3:     struct ini_item_t *next;
   4:     char *name;
   5:     char *value;
   6: } INIITEM, *LPINIITEM;
   7:  
   8: typedef struct ini_section_t {
   9:     struct ini_section_t *prev;
  10:     struct ini_section_t *next;
  11:     char *name;
  12:     int itemCount;
  13:     struct ini_item_t *first_item;
  14:     struct ini_item_t *last_item;
  15: } INISECTION, *LPINISECTION;
  16:  
  17: typedef struct ini_file_t {
  18:     char *name;
  19:     int sectionCount;
  20:     struct ini_section_t *first_section;
  21:     struct ini_section_t *last_section;
  22:     int flag;
  23:     char mode[8];
  24: } INIFILE, *LPINIFILE;

INIFILE用来描述一个ini文件,它内部的first_section和last_section用来表示一个链表,这个链表的成员节点即为INISECTION,它描述了当前这个ini文件里包含了哪些section区段;

INISECTION用来描述ini文件内的一个section,它本身是一个链表的节点,它内部的first_item和last_item用来表示另外一个链表,这个链表描述的就是当前这个section里包含了哪些条目;

INIITEM是最基础的结构体定义,它描述了一个item的信息。

 

一个INIFILE代表了一个ini文件,这个INIFILE内可能有若干个section,这些section形成了一个链表;

初始化INIFILE的过程如下:

   1: static LPINIFILE ini_createIniStruct(const char *name)
   2: {
   3:     LPINIFILE iniFile = (LPINIFILE)malloc(sizeof(INIFILE));
   4:     iniFile->name = (char *)malloc(strlen(name) + 1);
   5:     strcpy(iniFile->name, name);
   6:     iniFile->first_section = NULL;
   7:     iniFile->last_section = NULL;
   8:     iniFile->sectionCount = 0;
   9:     iniFile->flag = 0;
  10:     return iniFile;
  11: }
  12:  
  13: static void ini_destryIniStruct(LPINIFILE iniFile)
  14: {
  15:     LPINISECTION sec = iniFile->first_section;
  16:     free(iniFile->name);
  17:     while(sec)
  18:     {
  19:         LPINISECTION tmp = sec->next;
  20:         ini_delSection(iniFile, sec);
  21:         sec = tmp;
  22:     }
  23:     free(iniFile);
  24: }

在初始化一个INIFILE结构体的过程中,主要是为INIFILE结构体内的数据分配空间,并将INIFILE里的INISECTION链表设置为空;

 

在某个section内,可能包含了若干个item,这些item在当前section内也形成了一个链表;

初始化一个INISECTION的过程如下:

   1: static LPINISECTION ini_addSection(LPINIFILE iniFile, const char *name)
   2: {
   3:     LPINISECTION sec = (LPINISECTION)malloc(sizeof(INISECTION));
   4:     sec->name = (char *)malloc(strlen(name) + 1);
   5:     strcpy(sec->name, name);
   6:     sec->first_item = NULL;
   7:     sec->last_item = NULL;
   8:     sec->itemCount = 0;
   9:     add_node((void**)&(iniFile->first_section), (void**)&(iniFile->last_section), sec);
  10:     return sec;
  11: }
  12:  
  13: static void ini_delSection(LPINIFILE iniFile, LPINISECTION sec)
  14: {
  15:     LPINIITEM item = sec->first_item;
  16:     free(sec->name);
  17:     while(item)
  18:     {
  19:         LPINIITEM tmp = item->next;
  20:         ini_delItem(sec, item);
  21:         item = tmp;
  22:     }
  23:     del_node((void**)&(iniFile->first_section), (void**)&(iniFile->last_section), sec);
  24:     free(sec);
  25: }

当需要向INIFILE添加一个section时,一方面需要创建出来INISECTION,并添加到INIFILE的链表内,另一方面,要初始化INISECTION内的INIITEM链表。

 

最后是item的操作:

   1: static LPINIITEM ini_addItem(LPINISECTION iniSection, const char *name, const char *value)
   2: {
   3:     LPINIITEM item = (LPINIITEM)malloc(sizeof(INIITEM));
   4:     item->name = (char *)malloc(strlen(name) + 1);
   5:     strcpy(item->name, name);
   6:     item->value = (char *)malloc(strlen(value) + 1);
   7:     strcpy(item->value, value);
   8:     add_node((void**)&(iniSection->first_item), (void**)&(iniSection->last_item), item);
   9:     iniSection->itemCount++;
  10:     return item;
  11: }
  12:  
  13: static void ini_delItem(LPINISECTION iniSection, LPINIITEM item)
  14: {
  15:     free(item->name);
  16:     free(item->value);
  17:     del_node((void**)&(iniSection->first_item), (void**)&(iniSection->last_item), item);
  18:     free(item);
  19:     iniSection->itemCount--;
  20: }

 

以上有关链表的操作,都调用了《一个通用的双向链表管理程序》一文中介绍的通用双向链表管理程序。因为有了这个程序的存在,才使得对ini文件进行操作时,对于INISECTION链表和INIITEM链表可以使用相同的操作方法,调用相同的函数。

 

有了描述ini文件的数据结构之后,剩下的就是如何将ini文件解析成相应的数据结构了:

   1: INIFILEHANDLE ini_open(const char *iniFile, const char *mode)
   2: {
   3:     char lineBuf[1024];
   4:     LPINIFILE file;
   5:     LPINISECTION curSection = NULL;
   6:     FILE *fp;
   7:     fp = fopen(iniFile, mode);
   8:     if(fp == NULL)
   9:         return NULL;
  10:     file = ini_createIniStruct(iniFile);
  11:     strcpy(file->mode, mode);
  12:     while(fgets(lineBuf, 1023, fp))
  13:     {
  14:         char *p = strtrim(lineBuf);
  15:         int len = strlen(p);
  16:         if(strlen(p) <= 0)
  17:             continue;
  18:         else if(p[0] == '#')
  19:             continue;
  20:         else if((p[0] == '[') && (p[len - 1] == ']'))
  21:         {
  22:             p[len - 1] = '';
  23:             p = strtrim(&p[1]);
  24:             curSection = ini_addSection(file, p);
  25:         }
  26:         else
  27:         {
  28:             char *p2 = strchr(lineBuf, '=');
  29:             if(p2 == NULL)
  30:             {
  31:                 ini_destryIniStruct(file);
  32:                 file = NULL;
  33:                 break;
  34:             }
  35:             *p2++ = '';
  36:             p = strtrim(p);
  37:             p2 = strtrim(p2);
  38:             ini_addItem(curSection, p, p2);
  39:         }
  40:     }
  41:     fclose(fp);
  42:     return (INIFILEHANDLE)file;
  43: }

这个过程不复杂,主要是分析“[”和“]”界定符,以便判断section的入口,然后解析接下来的item,并添加到INISECTION中。

接着是将数据结构所描述的ini信息保存成一个ini文件:

   1: static void ini_writeItem(FILE *fp, LPINIITEM item)
   2: {
   3:     fprintf(fp, "%s=%sn", item->name, item->value);
   4: }
   5:  
   6: static void ini_writeSection(FILE *fp, LPINISECTION sec)
   7: {
   8:     LPINIITEM item = sec->first_item;
   9:     fprintf(fp, "[%s]n", sec->name);
  10:     while(item)
  11:     {
  12:         ini_writeItem(fp, item);
  13:         item = item->next;
  14:     }
  15:     fprintf(fp, "n");
  16: }
  17:  
  18: int ini_SaveTo(INIFILEHANDLE ini, FILE *fp)
  19: {
  20:     LPINIFILE iniFile = (LPINIFILE)ini;
  21:     LPINISECTION sec = iniFile->first_section;
  22:     if(fp == NULL)
  23:         return -1;
  24:     fprintf(fp, "# %sn", iniFile->name);
  25:     while(sec)
  26:     {
  27:         ini_writeSection(fp, sec);
  28:         sec = sec->next;
  29:     }
  30:     return 0;
  31: }

 

基本上就是这个样子了,下面把API贴出来吧:

   1: // INI句柄
   2: typedef void *INIFILEHANDLE;
   3: // 打开一个ini文件
   4: //    iniFile: ini文件路径
   5: //    mode: 打开方式, 与fopen的第二个参数意义相同
   6: INIFILEHANDLE ini_open(const char *iniFile, const char *mode);
   7: // 将ini文件另存到一个I/O流
   8: int ini_SaveTo(INIFILEHANDLE ini, FILE *fp);
   9: // 将ini文件另存为
  10: int ini_saveAs(INIFILEHANDLE ini, const char *saveFile);
  11: // 关闭ini文件
  12: void ini_close(INIFILEHANDLE ini);
  13: // 从ini文件读取一个字符串类型的属性值
  14: char *ini_ReadString(INIFILEHANDLE ini, const char *secName, const char *itemName, char *outBuf, const char *Default);
  15: // 从ini文件读取一个整数类型的属性值
  16: int ini_ReadInt(INIFILEHANDLE ini, const char *secName, const char *itemName, int Default);
  17: // 向ini文件写入一个字符串类型的属性值,如果ini文件没有该属性,则创建
  18: int ini_WriteString(INIFILEHANDLE ini, const char *secName, const char *itemName, const char *value);
  19: // 向ini文件写入一个整数类型的属性值,如果ini文件没有该属性,则创建
  20: int ini_WriteInt(INIFILEHANDLE ini, const char *secName, const char *itemName, int Value);

http://lameck.blog.163.com/blog/static/38811374200921614436213/

最后

以上就是笨笨百褶裙为你收集整理的一个用标准C写的ini文件操作程序的全部内容,希望文章能够帮你解决一个用标准C写的ini文件操作程序所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部