简介
这是《操作系统进阶》课上的project0的project_b部分内容。主要是练习用C语言进行文件的相关操作。这个project的要求是:
编写一个名为kv.c的程序,它是对持久键值对存储系统(比如FaceBook的RocksDB 和 Google的LevelDB )的简单模拟实现,这里用file来实现持久性的要求,即对file进行一系列操作。要求实现以下指令:
- put:格式为
p,key,value
,其中 key 是整数,值为任意字符串(其中没有逗号)。向file中插入键值对。 - get:格式为
g,key
,其中 key为整数。如果存在该键,系统应打印出该键,key,value
,后跟换行符 (\n)。如果不存在,则在找不到 K 形式的行上单独打印一条错误消息,其中 K 是键的实际值,即某个整数。 - delete:格式为
d,key
,它要么删除相关的键值对(并且不打印任何内容),要么不这样做(并且打印 K,其中 K 是键的实际值,即某个整数)。 - clear:格式为
c
。此命令只是从数据库中删除所有键值对。 - all:格式为
a
。此命令按任意顺序打印出数据库中的所有键值对,每行一个键值对,每个键和值用逗号分隔。
例:在Linux上运行kv文件中的put指令
prompt> ./kv
prompt> ./kv p,10,remzi
prompt> ./kv p,20,andrea p,40,someotherperson
结果会产生一个file,其内容如下
prompt> cat database.txt
20,andrea
40,someotherperson
prompt>
运行get指令及其结果:
prompt> ./kv g,10
10,remzi
prompt>
注意:对潜在错误的处理:
- 错误指令:如果命令行指定了错误的命令,例如,不是p,g,a,c或d的东西,请在一行上打印出警告错误命令,并继续处理命令行的其余部分;重要的是,不要退出。
- 意外错误:在任何意外的错误条件下,例如 malloc() 失败或无法成功打开文件,请打印出有用的错误消息并退出。
以下是我写的代码,由于时间有限没有来得及优化,只测试了部分数据,如有bug欢迎指正。后续有时间再来优化一下。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define M 100
struct data{
char c[10];
char key[10];
char value[M];
};
int main()
{
FILE *fp;
fp= fopen("file.txt","w+");//创建文件
if(fp==NULL)
{
printf("文件创建错误");
return(-1);
}
char instruction[M]={0};
while(scanf("%s",instruction)!=EOF)
{
struct data inst;
memset(inst.c,0,10);
memset(inst.key,0,10);
memset(inst.value,0,M);
char *buf;
buf=instruction;
char*token;
int i=0;
int j=0,k=0;
while(instruction[i]!='\0')//分割指令
{
j=0;
k++;
while(instruction[i]!=','&&instruction[i]!='\0')
{
if(k==1)
{
inst.c[j++]=instruction[i];
i++;
}
if(k==2)
{
inst.key[j++]=instruction[i];
i++;
}
if(k==3)
{
inst.value[j++]=instruction[i];
i++;
}
}
i++;
}
if(strcmp(inst.c,"p")==0)//put指令
{
fp= fopen("file.txt","a");//向文件写入但不覆盖
if(fp==NULL)
{
printf("打开文件错误");
return(-1);
}
fprintf(fp,"%s",inst.key);
fprintf(fp,"%s",",");
fprintf(fp,"%s\n",inst.value);
fclose(fp);
}
else if(strcmp(inst.c,"g")==0)//get指令
{
char line[M]={0};
fp= fopen("file.txt","rt");
if(fp==NULL)
{
printf("打开文件错误");
return(-1);
}
while(1)
{
if(EOF == fscanf(fp,"%s",line))
{
printf("%d not found\n",atoi(inst.key));
break;
}
//printf("%s",line);
int temp=0,ans=0,t=0;
ans=atoi(inst.key);
while(line[t]!=','&&line[t]!='\0')
{
temp*=10;
temp+=(line[t]-'0');
t++;
}
// printf("line:%s\n",line);
// printf("temp:%d\n",temp);
if(temp==ans)
{
printf("%s\n",line);
break;
}
}
fclose(fp);
}
else if(strcmp(inst.c,"d")==0)//delete指令
{
char lin[M]={0};
fp= fopen("file.txt","r+");
FILE*fp1= fopen("temp.txt","w+");
if(fp==NULL||fp1==NULL)
{
printf("打开文件错误");
return(-1);
}
int flg=0;
while(1)
{
if(EOF == fscanf(fp,"%s",lin))
{
if(flg==0)
{
printf("d:%d not found\n",atoi(inst.key));
}
break;
}
int temp=0,ans=0,t=0;
ans=atoi(inst.key);
while(lin[t]!=','&&lin[t]!='\0')
{
temp*=10;
temp+=(lin[t]-'0');
t++;
}
// printf("line:%s\n",line);
// printf("temp:%d\n",temp);
if(temp==ans)
{
flg=1;
}
if(temp!=ans)//不是要删的内容就写入temp
{
//printf("%s\n",line);
fwrite(lin, sizeof(lin),1, fp1);
// break;
}
}
fclose(fp);
fclose(fp1);
//remove("file.txt");
// rename("temp.txt","file.txt"); 出现了错误 不懂
fp=fopen("file.txt","w+");//刷新文件
fp1=fopen("temp.txt","r");
while(fread(lin,sizeof(lin),1,fp1))
{
fwrite(lin, sizeof(lin), 1, fp);
}
fclose(fp);
fclose(fp1);
}
else if(strcmp(inst.c,"c")==0)//clear指令
{
fp= fopen("file.txt","w");
//只要以 可写 的方式打开文件,就能将这个文件清空
if(fp==NULL)
{
printf("打开文件错误");
return(-1);
}
}
else if(strcmp(inst.c,"a")==0)//all指令
{
char Lin[M]={0};
fp=fopen("file.txt","rt");//权限问题要注意
// printf("test\n");
/* while(fread(Lin,sizeof(Lin),1,fp))
{
printf("%s\n",Lin);
} */
while(1)
{
if(EOF == fscanf(fp,"%s",Lin))
{
break;
}
printf("%s\n",Lin);
}
fclose(fp);
}
else{
printf("Bad command\n");
continue;
}
}
fclose(fp);
}
之前没写过C语言的文件操作,边查资料边完成了。这个例子对文件操作的运用还是很有参考意义的,故记录一下。