【文件】配置文件读写
2014-08-17 14:20
169 查看
配置文件接口设计思路
配置文件后缀名为“ini” 其图标一般如下: |
1.写配置文件 WriteCfgFile(FILE *fp, char *key, char val); //如果定义函数接口需要在此函数外部就要打开文件了,这给调用该函数的人带来一定麻烦,这就属于模块划分不合理了。 //所以一般情况下是在此文件中打开文件,而调用该函数的人只需要告诉该函数需要打开的那个文件名即可。 //所以将此函数改进成如下。 WriteCfgFile(char *fname, char *key, char val); //这里Master好像是说:万一fname所指文件中含有不可见字符,则...(啥玩意儿,没听清)...,所以要对上述函数再做些改进,如下所示。 WriteCfgFile(char *fname, char *key, int keylen, char val, int val_len); 2.读配置文件与写配置文件类似,这里就不多说了。 |
配置文件读写操作
直接看下面的例子 |
config.h |
#ifndef _CONFIG_H_ #define _CONFIG_H_ int GetCfgItem(char *pFileName, char *pKey, char *pValue, int *pValueLen); int SetCfgItem(char *pFileName, char *pKey, char *pValue, int *pValueLen); int WriteCfgItem(char *pFileName, char *pItemName, char *pItemValue, int itemValueLen); #endif |
|
config.c |
#include "config.h" #include "stdio.h" #include "string.h" #define LineMaxLen 2048 #define KeyMaxLen 64 //实现流程 //1. 打开文件; //2. 循环读取读取文件每一行; //3. 解析每一行,若匹配key关键字,再进行value值得提取 //4. 提取value值时需要去除前后空格(级指针典型应用) int GetCfgItem(char *pFileName, char *pKey, char *pValue, int *pValueLen) { int rv = 0; FILE *fp = NULL; char lineBuf[LineMaxLen]; char *pTmp = NULL, *pBegin = NULL, *pEnd = NULL; if(pFileName == NULL || pKey == NULL || pValue == NULL || pValueLen == NULL) { rv = -1; printf("GetCfgItem() err: %d.\n", rv); goto End; } fp = fopen(pFileName, "r"); if(fp == NULL) { rv = -2; printf("GetCfgItem() call fopen() err: %d.\n", rv); goto End; } while(!feof(fp)) { //读每一行 memset(lineBuf, 0, sizeof(lineBuf)); pTmp = fgets(lineBuf, LineMaxLen, fp); if(pTmp == NULL) {break;} //若不含=号,则为非配置项 pTmp = strchr(lineBuf, '=');//函数返回一个指向str 中ch 首次出现的位置,当没有在str 中找ch到返回NULL。 if(pTmp == NULL) {continue;} //检查key是否在本行 pTmp = strstr(lineBuf, pKey); if(pTmp == NULL) {continue;} //调整到=右边,为获取value做准备 pTmp = strchr(lineBuf, '='); if(pTmp == NULL) {continue;} pTmp = pTmp + 1; //获取value起点 while(1) { if(*pTmp == ' ') { pTmp++; } else { pBegin = pTmp; if(*pBegin == '\n') { //没有配置value printf("配置项:%s 没有配置value \n", pKey); goto End; } break; } } //获取value结束点 while(1) { if(*pTmp == ' ' || *pTmp == '\n') {break;} else {pTmp++;} } pEnd = pTmp; //赋值 *pValueLen = pEnd - pBegin; memcpy(pValue, pBegin, pEnd-pBegin);//函数从pBegin中复制pEnd-pBegin 个字符到pValue中,并返回pValue指针。如果pValue 和pBegin 重叠,则函数行为不确定。 break; } End: if(fp != NULL) { fclose(fp); } return rv; } //实现流程 //循环读取文件每一行,检查key关键字是否存在,若存在则修改对应的value值;若不存在,则在文件末尾添加“key = value”。 //难点:如何修改文件流中的值 int SetCfgItem(char *pFileName, char *pKey, char *pValue, int *pValueLen) { //参数pValueLen在本函数中没有被用到。 int rv = 0, iTag = 0, length = 0; FILE *fp = NULL; char linebuf[LineMaxLen]; char *pTmp = NULL, *pBegin = NULL, *pEnd = NULL; char filebuf[1024*8] = {0}; if(pFileName == NULL || pKey == NULL || pValue == NULL) { rv = -1; printf("func SetCfgItem() err: %d.\n",rv); goto End; } fp = fopen(pFileName, "r+");//以读写方式打开一个已存在的字符文件 if(fp == NULL) { rv = -2; printf("func SetCfgItem() call fopen() err: \n",rv); //goto End; } if(fp == NULL) //如果文件打开失败,则新建一个文件。 { fp = fopen(pFileName, "w+t");//打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 if(fp == NULL) { rv = -3; printf("func SetCfgItem() call fopen() err: \n",rv); goto End; } } fseek(fp, 0L, SEEK_END); //把文件指针从文件尾向文件头方向移动个字节,即将文件指针移到文件尾。(文件尾:联想一篇文章的末尾;文件头:联想一篇文章的开头) length = ftell(fp); //获取文件长度 fseek(fp, 0L, SEEK_SET); //把文件指针从文件头向文件尾方向移动个字节,即将文件指针移到文件头。 if(length > 1024*8) { rv = -3; printf("文件超过*8,nunsupport."); goto End; } while(!feof(fp))//判断是否到达文件尾 { //读每一行 memset(linebuf, 0, sizeof(linebuf));//将lineBuf清为 pTmp = fgets(linebuf, LineMaxLen, fp);//读取fp文件中当前行字符串到linebuf中,并返回这个字符串的首地址。 if(pTmp == NULL)//若fgets()读到文件尾或出错,则返回NULL {break;} //pKey关键字是否在本行 pTmp = strstr(linebuf, pKey);//找出linebuf在pKey中首次出现的位置,并返回其地址。 if(pTmp == NULL)//如果没有找到则返回NULL { strcat(filebuf, linebuf);//将linebuf连接到filebuf中。 //continue;//多余的 } else//如果找到了linebuf在pKey中首次出现的位置 { sprintf(linebuf, "%s = %s\n", pKey, pValue);//如果找到了,则不管pValue是多少,都要按照pKey = pValue格式写入linebuf中。 strcat(filebuf, linebuf);//将linebuf连接到filebuf中。 iTag = 1;//将iTag置,表示fp文件中存在pKey。 } } if(iTag == 0)//若不存在,则追加 { fprintf(fp, "%s = %s\n", pKey, pValue); } else//若存在pKey { if(fp != NULL) { fclose(fp); fp = NULL; //避免野指针 } fp = fopen(pFileName, "w+t"); //(me)上面的这个先关闭然后又打开文件,其用意是为了让文件指针回到文件起始位置,这用下面这条语句也可以代替。 //fseek(fp, -length, SEEK_END); if(fp == NULL) { rv = -4; printf("func SetCfgItem() call fopen() err: \n",rv); goto End; } fputs(filebuf, fp);//把filebuf中的字符串写入到由fp指向的文件中。 } End: if(fp != NULL) { fclose(fp); } return rv; } |
|
main.c |
#include "stdio.h" #include "stdlib.h" #include "string.h" #define DB_sid "oracle_sid" #define DB_User "appuser" #define DB_PassWord "appuser" #define CFG_FILENAME "F:\\Cpp_ChuanZhi\\MyProject\\demo1\\demo1\\cfg.ini" #include "config.h" void main_menu() { printf("\n1 Test SetCfgItem(测试设置配置文件) "); printf("\n2 Test GetCfgItem(测试读取配置文件) "); printf("\n0 exit(0) (程序退出) "); printf("\nplease enter your choice:[1/2/0]: "); } int Test_SetCfgItem() { int rv = 0; int choice = 0; char key[1024] ; char value[1024]; memset(key, 0, sizeof(key)); memset(value, 0, sizeof(value)); printf("\nplease enter key:"); scanf("%s", key); printf("\nplease enter value:"); scanf("%s", value); //rv = SetCfgItem(CFG_FILENAME, key, value, strlen(value)); rv = SetCfgItem(CFG_FILENAME, key, value, NULL); if (rv != 0) { printf("SetCfgItem() err: %d \n", rv); goto End; } printf("读写配置项(绿灯) 测试通过\n"); End: return rv; } int Test_GetCfgItem() { int rv = 0; int choice = 0; char key[1024] ; char value[1024]; int valueLen = 1024; memset(key, 0, sizeof(key)); memset(value, 0, sizeof(value)); printf("\nplease enter key:"); scanf("%s", key); //printf("\nplease enter value:"); //scanf("%s", value); rv = GetCfgItem(CFG_FILENAME, key, value, &valueLen); if (rv != 0) { printf("SetCfgItem() err: %d \n", rv); goto End; } printf("\n%s = %s", key, value); printf("\n读写配置项(绿灯) 测试通过\n"); End: return rv; } int main() { int rv = 0; int choice = 0; for(;;) { main_menu(); scanf("%d", &choice); switch (choice) { case 1: Test_SetCfgItem(); break; case 2: Test_GetCfgItem(); break; case 0: exit(0); default: exit(0); } } getchar(); return rv; } 输出结果如下: |
|
为了理清SetCfgItem()函数的逻辑顺序,这里画出了它的流程图如下。 |
|
相关文章推荐
- 一种简便实效的配置文件读写方法
- C#读写配置文件
- 读写配置文件
- .net2.0 使用configurationmanager读写配置文件
- C语言读写配置文件
- 用java读写ini配置文件
- XML格式的网站配置文件常见读写方案比较(转载)
- 用java读写ini配置文件的原因以及实现 示例
- 一种简便实效的配置文件读写方法
- Web 下配置文件信息的读写
- 用API读写INI配置文件
- 对项目配置文件app.comfig进行读写操作
- 读写INI配置文件的Java类
- 读写配置文件app.config
- 读写xml配置文件
- 用java读写ini配置文件(转)
- 为你的程序/系统提供强大的配置功能(选项配置文件的读写)
- 读写配置文件app.config
- 在C#中读写INI配置文件
- .Net2.0 使用ConfigurationManager读写配置文件