通过程序实现文件的读取操作
1.头文件声明
为了方便函数的调用,.c文件之间调用函数通常使用.h文件进行声明
,将需要用到的函数声明在.h文件中。
首先我们要读取的文件内容为
#这是我的的ip地址
ip:127.0.0.1
#这是我的端口
port:8080
#这是用户名
username:root
#这是密码
password:root
aaa:bbbb
cccc:dddd
其中#号开头的内容为注释内容为无效行,不需要读取,有效行格式为
key(关键字):value(有效值)
将要使用到的函数声明在config.h文件中,代码如下
//防止头文件重复包含
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct configInfo
{
char key[64];
char value[128];
};
//C++无法直接调用c的函数因此要写如下声明,使得编译器知道下面的内容是c语言函数
#ifdef _cplusplus
extern "c"{
#endif
//获得文件有效行数
int getLines_configFile(FILE *file);
//判断有效行
int validlines(const char * buf);
//加载文件
void loadfile_configfile(const char * filepath,char ***fileData,int * lines);
//解析文件
void parsefile_configfile(char **fileData,int lines,struct configInfo **info);
//获得指定文件信息
char * getinfo_configfile(const char * key,struct configInfo *info,int line);
//释放内存
void freeconfig(struct configInfo * info);
#ifdef _cplusplus
}
#endif
2.将函数实现
#include"configfile.h"
//判断有效行
int validlines(const char * buf)
{
/*由于有效行的格式为key(关键字):value(有效值)
因此判断有效行的条件为行首位置是否有# \n换行 内容中是否有':'
*/
if (buf[0]=='#' || buf[0]=='\n' || strchr(buf,':')==NULL )
{
return 0;//非有效行返回0
}
return 1;//有效行返回1
//获得文件有效行数
int getLines_configFile(FILE *file)
{
char buf[1024]={0};
int lines = 0;
while(fgets(buf,1024,file) != NULL)
{
if (!validlines(buf))
continue;
lines++;
memset(buf,0,1024);
}
fseek(file,0,SEEK_SET);//档获得有效行时,文件指针在文本末尾,需要返回到文件开头
return lines;
}
//加载配置文件参数为(文件路径,返回的文件内容,返回的有效行数)
void loadfile_configfile(const char * filepath,char ***fileData,int * line)
{
FILE *file =fopen(filepath,"r");
if (NULL == file)
{
return;
}
int lines = getLines_configFile(file);//获取有效行后,指针重定向到文件开头
char ** temp =(char **)malloc(sizeof(char *)* lines);//开辟空间接收文件内容
char buf[1024] = {0};//接收文件一行的内容
int index =0;//计数器
while (fgets(buf,1024,file) !=NULL)//判断接收的行是否为空
{
if(!validlines(buf))//判断是否是有效行无效进入下一次内容
continue;
temp[index]=(char *)malloc(strlen(buf)+1);
strcpy(temp[index],buf);//将有效信息导入到空间中
index++;
memset(buf,0,1024);//重置buf空间
}
* fileData = temp;//返回有效内容
* line =lines;//返回有效的行数
fclose(file);//关闭文件
}
//解析配置文件传递参数(有效的文件内容,有效行数,要传入的结构体)
void parsefile_configfile(char **fileData,int lines,struct configInfo **info)
{
struct configInfo * myinfo = (struct configInfo *)malloc(sizeof(struct configInfo)*lines);//开辟空间接收关键字和有效值
memset(myinfo,0,sizeof(struct configInfo)*lines);//重置空间
for(int i =0;i<lines;i++)
{
char * pos = strchr(fileData[i],':');//定位在行中':'的位置
strncpy(myinfo[i].key,fileData[i],pos-fileData[i]);//将key的内容传入结构体中的key值
if(strchr(fileData[i],'\n'))//由于配置信息中最后一行没有换行'\n'
strncpy(myinfo[i].value,pos+1,strlen(pos+1)-1);//有\n换行的
else
strncpy(myinfo[i].value,pos+1,strlen(pos+1));//没有\n换行的
}
*info = myinfo;//将整理好的结构体返回
for (int i = 0; i < lines; i++)//释放空间
{
if (fileData[i] != NULL)
{
free(fileData[i]);
}
}
}
//获得指定配置信息传递参数(查询值,结构体,有效行数)
char * getinfo_configfile(const char * key,struct configInfo *info,int line)
{
for (int i = 0; i < line; i++)
{
if (strcmp(key,info[i].key)==0)//判断查询值和文件中的有效值相同
{
return info[i].value;
}
}
return NULL;
}
//释放内存
void freeconfig(struct configInfo * info)//释放结构体内存
{
if ( NULL==info)
{
return;
}
free(info);
info =NULL;
}
}
3 调用函数实现查询功能
#include"configfile.h"
void test(char *str)
{
char **filedata;
int line;
struct configInfo *output=NULL;
//加载配置文件将有效内容返回filedata、line
loadfile_configfile("./config.ini",&filedata,&line);
//解析配置文件将有效内容依次传递到结构体output
parsefile_configfile(filedata,line,&output);
//打印要查看的配置信息
printf("%s: %s\n",str,getinfo_configfile(str,output,line));
//释放配置信息
freeconfig(output);
}
void main()
{
char str[1024]={0};
while (true)
{
printf("请输入要查看的配置信息:");
scanf("%s",str);
if(strcmp(str,"exit")==0)
{
break;
}
test(str);
}
}