成绩:
课程设计报告
课程名称:
Unix下C
设计题目:
报文解析之数据更新
姓 名:
专 业:
网络工程
班 级:
学 号:
计算机科学与技术学院
网络系
2013 年 12月 25 日
设计项目: 报文解析之数据更新
一、 选题背景
报文解析之数据更新:通过命令参数指定更新内容和更新条件,可模仿update语句。
文件中定义每个学生的相关信息,包括学号、学生姓名、年龄、性别、系别。针对当前题目可以将每一个学生的信息定义成固定长度格式,方便检索和更新。
例如指定程序名称为update
使用方法可指定为 update a.txt set dept=cs where s#=010101
二、 设计思路
完成文件update.c实现更新功能,更新格式如下:
update datafilename set fieldname1=value1 where fieldname2=value2
严格按照格式输入命令行参数,等号两边不能存在空格。每次只能改变一个字段的值Fuction部分用来专门设置具体实现函数功能过程,来完成更新功能。再更新过程中利用了三个函数来实现整个过程。
函数get_content是对fieldname=value的filename和value进行提取信息。
函数check是对每行信息检查是否符合where fieldname2=value2条件。
函数change是对每行符合where fieldname2=value2条件的信息,实现所需要的更新操作。
在这过程中为了数据的方便,编写了makedata.c来生成数据;由于对datafile进行了多次修改,内容的变化不利于多次测试,为了多次测试,编写了retest.c文件生成retest可执行程序来还原datafile的内容。
三、 主要问题的解决方法和关键技术
报文解析是UNIX应用的重要内容。报文解析利用到了对于文件的操作,打开文件,关闭文件,从文件流读取以及输出到文件流中,从文件流中读取一个字符串之后,对其信息进行提取,提取出所需要的信息。函数fopen打开或创建文件;fclose关闭文件;函数freopen重新打开文件;函数remove删除磁盘文件;函数rename更改文件名称。
双方把约定的几个域通过某种排序和分割方式组合在一起,形成报文。字符串报文是报文的重要分支,它以字符串为载体
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
了域的数据。在字符串报文中,域与域之间最常见的两种分割方式是固定长度分割和特殊字符(串)分割。行读写函数每次读取一行以换行符结束的数据,写入数据时自动输出换行符。利用行读写实现报文解析之数据更新。
在整个过程中遇到以下问题:
(1):如果进入Centos图像化界面,经过百度知道命令startx即可。
图3-1通过startx进入图形化界面
(2):开始程序一运行就崩溃,经过单步执行,发现int main(int argc,char *argv[])中*忘记写了,导致程序一直崩溃,即
图3-2 程序崩溃
(3):编译错误
图3-3编译错误
(4):fgets函数使用不熟练。出现输出信息缺少换行问题,即文件结果如图3-4所示。puts使用时会自动在后面加上换行,错误的认为fputs在输出一个字符串的时候也会自动加上换行,百度之后发现fputs并没有加上换行,那每一个字符串是如何实现换行的呢?查询
资料
新概念英语资料下载李居明饿命改运学pdf成本会计期末资料社会工作导论资料工程结算所需资料清单
fgets的用法,发现fgets的用法也不同于gets函数,特殊之处在于“ 如果遇到换行符,该换行符将被读入字符串,再在换行符后加一’\0’ ”;而在本次实验中所有的判断字符串结束时利用str[i]!=’\0’忽略了’\n’的存在导致每次查找最后一项时查找不到,更改最后一项时又出现输出格式的错误。
图3-4 更改信息缺少换行
这个问题是本次实验最大的收获,多出单步执行才检查到错误,以下是单步执行的过程:
图3-5 单步执行的代码
单步执行时候,对于同样的Math开始的时候,利用strcmp的结果并不是0,所以又将两个字符串分别用strlen函数测量出长度并输出,发现从报文中解析出来的Math的长度为5,而且与以上输出结果缺少换行问题,都是问题出现在了最后一个字母的部分,并且将fgets和fputs换掉之后,运行结果一切正常,所以可以知道是fgets和fputs的问题。
图3-6单步执行的结果
修改正确后输出单步执行的结果,发现现在结果已经正确,更改代码如下,将’\0’改为’\n’:
图3-7错误代码
图3-8正确代码
四、程序流程图
否
是
否
是
否
是
是
否
否
是
五、原程序清单
#include
#include
#include
/*该函数实现的是对dept=Math提取dept信息和Math信息,将类别以数字形式存在*type中,将内容存在content中,类型0、1、2、3、4分别表示s#、name、age、*sex、dept即类型所对应的数字正好符合每一项所在的几个冒号的后面,方便更改信息
*的处理,由于对于set和where两处都需要用到此查找方法,故写成函数形式,可以多*次调用实现同一功能*/
int get_content(char str[],char content[]){
int type=-1;
if(strncmp(str,"s#",2)==0){
type=0;
strcpy(content,str+3);
}else if(strncmp(str,"name",4)==0){
type=1;
strcpy(content,str+5);
}else if(strncmp(str,"age",3)==0){
type=2;
strcpy(content,str+4);
}else if(strncmp(str,"sex",3)==0){
type=3;
strcpy(content,str+4);
}else if(strncmp(str,"dept",4)==0){
type=4;
strcpy(content,str+5);
}
return type;
}
/*该函数实现的功能是是否满足where所对应的信息,如果符合where所需要的信息则
*返回0,否则返回1*/
int check(char str[],int type,char content[]){
int i,j;
char buf[256];
/*从头遍历字符串,将位置停在第type个冒号后面,故每找到一个冒号,则type--一直*到type为0为止。*/
for(i=0;type!=0;i++){
if(str[i]==':') type--;
}
/*将这个冒号后面到下一个冒号中间的信息提取出来存在buf中,但是如果信息是最后一
*个冒号后面的,即应该找到字符串最后,但是这里没有写str[i]!='\0',因为str
*字符串是由fgets从文件读取的,而fgets没读取一个字符串会将最后的换行也读进去,
*最后再加上一个'\0'*/
for(j=0;i,str[i]!='\n'&&str[i]!=':';i++){
buf[j++]=str[i];
}
/*给字符串封上口,即最后加上'\0',也可以在最一开始进行memset初始化*/
buf[j]='\0';
/*将提取出来的信息与原信息对比,看是否一致,即是否符合where的条件,符合则返回0,
*否则返回1*/
if(strcmp(buf,content)==0) return 0;
else return 1;
}
/*该函数实现的功能是将符合where条件的信息按照set的要求进行更改,并将更改的信
*息保存在str中具体实现细节和get_content函数相似 */
void change(char str[],int type,char content[]){
int i,j,k;
char buf[256];
for(i=j=0;type!=0;i++){
if(str[i]==':') type--;
buf[j++]=str[i];
}
for(;str[i]!='\n'&&str[i]!=':';i++);
for(k=0;content[k]!='\0';k++){
buf[j++]=content[k];
}
for(;str[i]!='\0';i++){
buf[j++]=str[i];
}
buf[j]='\0';
strcpy(str,buf);
return ;
}
int main(int argc,char *argv[]){
/*输入必须满足update a.txt set s#=1104020218 where dept=Math
*这种格式,其中第4项和第6项即 s#=1104020218 和 dept=Math是
*可以换的,但是也必须满足是s#、name、age、sex、dept中的某一项
*格式满足是“某一项=内容”,故先对命令进行
检测
工程第三方检测合同工程防雷检测合同植筋拉拔检测方案传感器技术课后答案检测机构通用要求培训
是否符合格式*/
if(argc!=6){
fprintf(stderr,"Input is invalid.\n");
return 1;
}
/*定义文件读入流和文件输出流,并打开文件argv[1](输入的文件名)
*文件打开失败则报错,并且函数返回1.*/
FILE *fpr,*fpw;
if((fpr=fopen(argv[1],"r"))==NULL){
fprintf(stderr,"open %s failed.\n",argv[1]);
return 1;
}
if((fpw=fopen("newfile","w"))==NULL){
fprintf(stderr,"open newfile failed.\n");
fclose(fpr);
return 1;
}
/*to和to_content分别是set dept=Math中的dept和Math的记录
*调用get_content函数提取to_content和to的信息*/
char to_content[64];
int to=get_content(argv[3],to_content);
/*from和from_content分别是where dept=Math中的dept和Math的记录
*调用get_content函数提取from_content和from的信息*/
char from_content[64];
int from=get_content(argv[5],from_content);
/*如果set和where的项都不是s#、name、age、sex和dept这几种,
*即输入不合法,则报错,并且函数返回1*/
if(from==-1||to==-1){
fprintf(stderr,"Input is invalid.\n");
return 1;
}
/*从目标文件每次读取一行信息并且check一下是否符合where的条件,
*只要符合where的条件,则将对应的信息进行更改,利用change函数
*实现,然后将该信息写入fpw文件流中*/
char buf[256];
while(fgets(buf,sizeof(buf),fpr)!=NULL){
if(check(buf,from,from_content)==0){
change(buf,to,to_content);
}
fputs(buf,fpw);
}
fclose(fpr);
fclose(fpw);
/*由于无法实现直接对文件中的信息进行更改,所以通过建立一个临时文件
*newfile把更改过的所有信息写入临时文件中,再将原来的文件删除,然后
*将newfile文件再重命名为原文件的名字即可*/
if(remove(argv[1])<0){
fprintf(stderr,"remove file failed.\n");
return 1;
}
if(rename("newfile",argv[1])<0){
fprintf(stderr,"Rename file failed.\n");
return 1;
}
return 0;
}
六、程序运行结果
图6-1文件a.txt内容
该图是执行命令update a.txt set name=sunshine where s#=1104020218之前的内容。
图6-2文件a.txt内容
经过命令update a.txt set name=sunshine where s#=1104020218将学号18的名字改为sunshine,即与图6-1对比可以发现执行完该命令后,学号18的姓名已更改。
图6-3文件a.txt内容
经过命令update a.txt set dept=English where name=sunshine将名字为sunshine的同学的专业改为English,即与图6-2对比可以发现执行完该命令后,姓名为sunshine的专业已更改。
图6-4文件a.txt和临时文件newfile
原文件a.txt和临时文件newfile的对比,通过命令update a.txt set s#=0000000000 where dept=Math命令,可以看出newfile中所有dept=Math的s#都是0000000000。
七、设计
总结
初级经济法重点总结下载党员个人总结TXt高中句型全总结.doc高中句型全总结.doc理论力学知识点总结pdf
通过本次课程设计,不仅熟练了文件操作函数的使用,并且对于fgets、fputs等函数有了更进一步的学习,走出了之前的误区,此次代码成功之处在于对于每一项需要更改的信息,即s#、name、age、sex、dept;由于知道了文件的格式,所以不需要每一项都写一个if,如果是有100项,甚至更多项,多个if语句不仅会让代码看起来不美观,并且会影响代码的执行效率,所以采用了数字表示类别,且数字同样记录了格式的优势,可以对于任意一项用同样的代码来进行实现,增加了对于不同文件的使用,移植性强。
主函数实现每一项功能即调用相应的函数,而不是将所有功能代码均写入main函数中,这样可以使主函数看起来清楚明了,并且可以多次调用使用同一功能,向每个函数传入形参或地址,形参保证了在主函数中该整形变量没有收到变化,地址是字符串,满足了更改字符串的要求。
在本次课程设计中不仅对于理论知识进行了学习,并且提高了自学能力,遇到很多问题,都是去网上查找相关资料,虽然会浪费一些时间,但是通过自己的努力查到的资料记忆更深刻。
总之,每一次课程设计不仅是我们学习的好机会,而且是我们锻炼实际动手能力的平台,虽然有难度的东西总会让人很抵触,比如在课设过程中有很多郁闷的时候,一个小小的错误一不小心就花去了自己一上午的时间,所以在这个过程中能够磨练人的意志与耐心,最后感谢老师的指导与监督。
附录A:代码
Updata.c
//s#:name:age:sex:dept
//update a.txt set dept=cs where s#=010101
#include
#include
#include
int get_content(char str[],char content[]){
int type=-1;
if(strncmp(str,"s#",2)==0){
type=0;
strcpy(content,str+3);
}else if(strncmp(str,"name",4)==0){
type=1;
strcpy(content,str+5);
}else if(strncmp(str,"age",3)==0){
type=2;
strcpy(content,str+4);
}else if(strncmp(str,"sex",3)==0){
type=3;
strcpy(content,str+4);
}else if(strncmp(str,"dept",4)==0){
type=4;
strcpy(content,str+5);
}
return type;
}
int check(char str[],int type,char content[]){
int i,j;
char buf[256];
for(i=0;type!=0;i++){
if(str[i]==':') type--;
}
for(j=0;i,str[i]!='\n'&&str[i]!=':';i++){
buf[j++]=str[i];
}
buf[j]='\0';
// fprintf(stderr,"check %s(%d) %s(%d)\n",buf,strlen(buf),content,strlen(content));
if(strcmp(buf,content)==0) {
// puts("yes!!!!!!!!!!!!!!!!");
return 0;
}else{
return 1;
}
}
void change(char str[],int type,char content[]){
int i,j,k;
char buf[256];
for(i=j=0;type!=0;i++){
if(str[i]==':') type--;
buf[j++]=str[i];
}
for(;str[i]!='\n'&&str[i]!=':';i++);
for(k=0;content[k]!='\0';k++){
buf[j++]=content[k];
}
for(;str[i]!='\0';i++){
buf[j++]=str[i];
}
buf[j]='\0';
strcpy(str,buf);
return ;
}
int main(int argc,char *argv[]){
if(argc!=6){
fprintf(stderr,"Input is invalid.\n");
return 1;
}
FILE *fpr,*fpw;
if((fpr=fopen(argv[1],"r"))==NULL){
fprintf(stderr,"open %s failed.\n",argv[1]);
return 1;
}
if((fpw=fopen("newfile","w"))==NULL){
fprintf(stderr,"open newfile failed.\n");
fclose(fpr);
return 1;
}
char to_content[64];
int to=get_content(argv[3],to_content);
// fprintf(stderr,"%s to_content=%s\n",argv[3],to_content);
char from_content[64];
int from=get_content(argv[5],from_content);
// fprintf(stderr,"%s from_content=%s\n",argv[5],from_content);
if(from==-1||to==-1){
fprintf(stderr,"Input is invalid.\n");
return 1;
}
char buf[256];
while(fgets(buf,sizeof(buf),fpr)!=NULL){
if(check(buf,from,from_content)==0){
change(buf,to,to_content);
}
fputs(buf,fpw);
}
if(remove(argv[1])<0){
fprintf(stderr,"Remove file failed.\n");
return 1;
}
if(rename("newfile",argv[1])<0){
fprintf(stderr,"Rename file failed.\n");
return 1;
}
return 0;
}
Retest.c
#include
void main(){
if(remove("a.txt")<0){
printf("Remove a.txt failed.\n");
return 1;
}
freopen("student","r",stdin);
freopen("a.txt","w",stdout);
char buf[256];
while(gets(buf)!=NULL){
puts(buf);
}
fclose(stdin);
fclose(stdout);
}
Makedata.c
#include
#include
#include
#include
void main(){
freopen("student","w",stdout);
srand( (unsigned)time(NULL));
int i,j;
char dept[10][10]={"Computer","Math","English"};
for(i=1;i<35;i++){
//num name age sex dept
int age=rand()%3+20;
int sex=rand()%2;
char name[10];
for(j=0;j<5;j++){
name[j]=rand()%26+'a';
}
name[j]='\0';
printf("11040202%02d:%s:%d:%d:%s\n",i,name,age,sex,dept[rand()%3]);
}
}