在项目里面经常会用到读取一些配置信息,而C语言有没有直接的读取配置文件的函数,这里贴出我写的代码,有兴趣的看一下,也希望能有好的建议。
考虑到代码需要在多个项目里面运行,会对配置文件有不同的需求,这里把文件路径封装在一个struct里面,方便在里面添加一些其他的变量,头文件声明如下:
hcof.c
/******************************************************************
* 用途: 配置文件读写 *
* 作者: uehang *
* 日期: 2013-3-28 *
*****************************************************************/
#ifndef HCONF_H
#define HCONF_H
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
typedef struct h_conf{
char file_path[200];
}HConf;
void init_conf(HConf *hconf, char *file_path);
/*
* return: -1:fail to open file; 0: can not find the key; 1: success
*/
int get_conf_value(HConf *hconf, char *key_name, char *value);
/*
* return: -1:fail to open file; 0: can not find the key; 1: success
*/
int set_conf_value(HConf *hconf, char *key_name, char *value);
#endif
首先,初始化函数,对当前的情况来说,只负责把参数file_path的值传递到参数hcnf的file_path变量,这里单独写成一个函数,不仅是让get_conf_value()和set_conf_value()在调用时避免写一长串的file_path,也是方便在有特殊需求的情况下,对文件名进行检验或对文件进行预处理。
get_conf_value()与set_conf_value()负责读写文件,由于配置文件多是在程序启动或者特殊时刻才会读取,所以没有必要一直打开文件。
hconf.c
#include "hconf.h"
void init_conf(HConf *hconf, char *file_path)
{
int fd=open(file_path,O_RDONLY);
if(fd>2){ //确保文件存在
close(fd);
strcpy(hconf->file_path,file_path);
}else{
perror("can not open config file:");
}
}
int get_conf_value(HConf *hconf, char *key_name, char *value)
{
int res;
int fd = open(hconf->file_path,O_RDONLY);
if(fd > 2){
res = 0;
char c;
char *ptrk=key_name;
char *ptrv=value;
while((read(fd,&c,1))==1){
if(c == (*ptrk)){
do{
ptrk ++;
read(fd,&c,1);
}while(c == (*ptrk));
if(c=='='&&(*ptrk)=='\0'){
while(1)
{
read(fd,&c,1);
if(c != '\n')
{
(*ptrv) = c;
ptrv ++;
}else{
(*ptrv) = '\0';
break;
}
}
res = 1;
break;
}else{
do{
read(fd,&c,1);
}while(c != '\n');
}
}else{
do{
read(fd,&c,1);
}while(c != '\n');
}
}
close(fd);
}else{
res = -1;
}
return res;
}
int set_conf_value(HConf *hconf, char* key_name, char *value)
{
int res;
int fd = open(hconf->file_path,O_RDONLY);
if(fd > 2){
char buf[800]; //存储文件内容
res = 0;
char c;
char *ptrk=key_name;
char *ptrv=value;
char *ptrb=buf;
while((read(fd,&c,1))==1){
*ptrb = c;
if(c == *ptrk){
do{
ptrb ++;
ptrk ++;
read(fd,&c,1);
*ptrb = c;
}while(c == *ptrk);
if(c == '=' && *ptrk == '\0'){//找到目标行
do{
ptrb ++;
*ptrb = *ptrv;
ptrv ++;
}while(*ptrv != '\0'); //将value赋值给buf
while((read(fd,&c,1)) == 1 && c != '\n');//等号右边原来的内容舍弃
ptrb ++;
*ptrb = '\n';
}else { //非目标行全部读取
while((read(fd,&c,1)) == 1){
ptrb ++;
*ptrb = c;
if(c == '\n'){
break;
}
}
}
}else{ //非目标行全部读取
while((read(fd,&c,1)) == 1){
ptrb ++;
*ptrb = c;
if(c == '\n'){
break;
}
}
}
ptrb ++;
}
*ptrb = '\0'; //循环结束,buf末尾置'\0'
close(fd);
fd=open(hconf->file_path,O_WRONLY|O_TRUNC);//截短打开文件,写入buf
if(fd > 2){
write(fd,buf,strlen(buf));
close(fd);
res = 1;
}
}else{
res = -1;
}
return res;
}
所有打开的文件都有一个当前文件偏移量(current file offset),可以简称为 cfo。cfo 通常是一个非负整数,用于表明文件开始处到文件当前位置的字节数。读写操作通常开始于 cfo,并且使 cfo 增大,增量为读写的字节数。文件被打开时,cfo 会被初始化为 0,除非使用了 O_APPEND 。这里通过每次的read()和write()函数来改变偏移量,使定位准确。
由于c语言中的文件是以数据流的形式来进行读写的,无法直接进行插入、删除的操作,这里把文件内容经处理后全部读取到内存里面,然后从内存写入到原文件里面,实现对文件的修改。
测试
这里用一个简单的文件测试一下
main.c
#include <stdio.h>
#include <stdlib.h>
#include "hconf.h"
int main()
{
HConf *info = (HConf *) malloc(sizeof(HConf));
init_conf(info,"./info.conf");
char buf[20];
get_conf_value(info,"email",buf);
printf("email = %s --get from info\n",buf);
set_conf_value(info,"age","115 years old");
printf("set info:age = 115 years old\n");
return 0;
}
结果:
原info.conf 运行后info.conf
总结
总的来说,是实现了基本读写功能,而且只用了文件操作的open()、read()、write()这三个函数,而在测试时也发现,对中文的比较和判断会出错,若有大侠路过,也恳求指点。