操作系统课程设计报告模拟文件管理目)院系:计算机科学技术学院计算机科学与技术系班级:计07--2 班姓名:刘德庆学号:12指导教师:鲁静轩2009 年6 月15 日操作系统课程设计任务书一、设计题目:模拟文件管理二、设计目的《操作系统原理》课程设计是软件工程专业实践性环节之一,是学习完《操作系统原理》课程后进行的一次较全面的综合练习。
其目的在于加深对操作系统的理论、方法和基础知识的理解,掌握操作系统结构、实现机理和各种典型算法,系统地了解操作系统的设计和实现思路,培养学生的系统设计能力,并了解操作系统的发展动向和趋势。
三、设计要求(1)选择课程设计题目中的一个课题,合作完成。
(2)良好的沟通和合作能力(3)充分运用前序课所学的软件工程、程序设计等相关知识(4)充分运用调试和排错技术(5)简单测试驱动模块和桩模块的编写(6)查阅相关资料,自学具体课题中涉及到的新知识。
(7)课题完成后必须按要求提交课程设计报告,格式规范,内容详实四、设计内容及步骤1.根据设计题目的要求,充分地分析和理解问题,明确问题要求做什么。
2.根据实现的功能,划分出合理的模块,明确模块间的关系。
3.编程实现所设计的模块。
4.程序调试与测试。
采用自底向上,分模块进行,即先调试低层函数。
能够熟练掌握调试工具的各种功能,设计测试数据确定疑点,通过修改程序来证实它或绕过它。
调试正确后,认真整理源程序及其注释,形成格式和风格良好的源程序清单和结果;5.结果分析。
程序运行结果包括正确的输入及其输出结果和含有错误的输入及其输出结果。
6.编写课程设计报告;设计报告要求:A4纸,详细设计部分主要叙述本人的工作内容五、课程设计工作计划设计在学期的第15、16周进行,时间安排如下:序号内容时间(天)1 预习、讲课 12 设计 33 编码、测试 54 验收 1合计10。
六、成绩评定办法成绩分为优(A)、良(B)、中(C)、及格(D)、不及格(E)五个等级。
其中设计表现占30%,验收40%,设计报告占30%。
1.设计表现:教师可依据学生使用实验环境的能力、观察和分析实验现象的能力、实验结果和数据的正确性以及学生的课堂纪律、实验态度、保持实验室卫生等方面的表现进行综合考核。
2.验收:要求学生演示设计的程序,讲解设计思路、方法、解决的主要问题,教师根据具体情况向每个学生提问2至3个问题。
3.设计报告:学生设计后应按时完成设计报告。
要求:内容充实、写作规范、项目填写正确完整、书面整洁等。
目录一.需求分析 (4)二.概要设计 (5)三.详细设计 (6)四.调试分析,测试结果 (25)五.用户使用说明 (25)六.附录,参考资料 (27)一需求分析阅读操作系统方面的书籍,了解操作系统的文件系统原理。
结合分析课程设计要求,确定实体以及它们之间的关系。
实体关系有三张表(磁盘空间分配表、文件表、打开文件表)、一个模拟磁盘的数组、命令服务和用户构成。
用户负责输入命令。
命令服务实现命令的解释、命令检查、命令帮助以及调用相关模块执行相应的命令功能。
程序功能图实体关系图用户命令服务模拟磁盘磁盘空间分配表文件表打开文件表模拟文件系统创建文件删除文件条件读取写入文件查询属性显示内容显示目录重命名文件关闭文件命令服务使得用户能够输入命令,在需要时提供命令的帮助。
同时能够分析命令,调用相应的命令模块对模拟磁盘、磁盘空间分配表、文件表、打开文件表进行操作。
磁盘空间分配表记录模拟磁盘的使用情况。
文件表记录文件的信息和在磁盘里的位置等信息。
打开文件表记录已打开的文件,对应文件表中的文件信息,和文件表里的文件节点类似,记录了文件在模拟磁盘中的信息。
数据流图构造这些实体的关系图,数据流图、程序流程图来进行具体的设计。
通过模拟文件系统的实现,深入理解操作系统中文件系统的理论知识, 加深对教材中的重要算法的理解。
同时通过编程实现这些算法,更好地掌握操作系统的原理及实现方法,提高综合运用各专业课知识的能力。
二 概要设计此课程设计把TXT 文本作来研究对象来模拟操作系统的文件系统工作过程。
所以用一个字符串数组来模拟磁盘空间,顾名思义,模拟磁盘提供字符的存储服务。
磁盘空间分配表,采用链表结构,每个节点保存模拟磁盘的一个逻辑块的信息,包括块的最大长度,文件占用长度,占用标志。
如果占用标志为0,即该空间可分模拟文件系统输入界面显示命令帮助文件表打开文件表磁盘分配表模拟磁盘显示信息文件信息文件信息 长度、位置信息文件(字符串)用户命令配给文件。
初始化磁盘空间分配表链表,首先把整个模拟磁盘作来一块,并置占用位为0.当有进程申请磁盘空间时,从头开始遍历,检查占用位,如果该块为可分配,则检查块大小,若块长度大于或等于申请空间大小,则把块的前一部分(等于申请大小)分配给文件,并置标志位为占用。
剩下的大小作来一个新块,作来一个新节点插入到原节点的后边,标志位为可用。
这样就实现了模拟磁盘的线性分配。
文件表,由于模拟文件系统的文件数量不多,故文件表采用线性表来存储。
线性表每个结点存储一个文件的信息。
打开文件表,采用数组形式存储打开的文件,数组每个元素保存一个打开文件的信息。
文件信息和文件表中的文件信息类似。
这个系统完成了需求分析阶段所要求的:文件系统提供的文件操作有建立文件(create)、删除文件(delete)、条件读取文件(read)、写入文件(write)、查询文件的属性(ask)、显示文件所有内容(type)、重命名文件(ren)、关闭文件(close)。
可以通过键盘输入命令来模拟文件的操作。
通过exit命令退出程序。
这个课程设计,用到的知识如下:1.文件的物理结构可以选用顺序分配、链表分配或索引分配。
2.建立文件:从命令中得到文件名,得到该文件的文件长度,建立文件。
修改目录表。
3.删除文件:回收文件占用的空间,修改目录表4.读文件:read [文件名] [显示开始字节] [显示的字节数] ,直接显示所需要的字节数。
5.写文件:write [文件名] [插入的位置] [插入的内容]6.查询属性:显示文件属性文件名,类型,长度,时间等。
三详细设计数据结构设计通过分析课程设计要求,具体设计出如下数据结构:①char disk[10000]; //模拟磁盘空间通过一个字符串数组来模拟磁盘空间,数组最大长度设置为10000,即磁盘空间最大容量为10000字节。
作为模拟文件系统,主要理解文件系统的原理,可以把文本文件作为对象来研究。
故磁盘空间用一个字符串数组来模拟.②struct freeDiskTable //碰盘空间分配表{int start; //开始位置int length; //占用长度int maxLength; //最大长度int useFlag; //使用标志,1为占用,0为空闲};通过结构体,将磁盘空间使用情况(文件开始位置、占用长度、最大长度、使用标志)结合在一体。
一个结构体变量记录磁盘一个块的信息。
结构体作为链表的一个节点,设置一个链表将节点连接起来,构成一个磁盘空间分配表。
③struct fileTable //文件表{c har fileName[20]; //文件名字int start; //开始位置i nt length; //文件长度i nt maxLength; //最大长度char fileKind[8]; //文件种类,此默认为txts truct tm *timeinfo; //文件创建时间};通过结构体,将文件名字、文件在磁盘的开始位置、文件长度、文件最大长度、文件类型、创建时间结合在一起。
文件类型,本模拟程序使用txt类型。
设置一个线性表来存储文件。
④struct openFileTable // 打开文件表{char fileName[20]; //文件名字c har fileKind[8]; //文件类型i nt start; //文件开始位置int length; //文件长度i nt maxLength; //最大长度int openCount; //打开文件的进程数struct tm *timeinfo; //文件创建时间};通过结构体存储打开的文件信息,包括文件名字、文件类型、文件开始位置、文件长度、最大长度、文件打开数和文件创建时间。
通过结构体数组存储所有打开文件信息。
程序流程图模拟文件系统提供的文件操作有建立(create),读取(read),显示(type),删除(detele),写入(write),关闭(close),重命名(ren)和查询(ask)。
在模拟程序中可从键盘上输入文件操作命令来模拟各用户程序中所调用的各种文件操作,用一个结束命令(exit)停止程序的执行。
开始初始化命令表初始化文件表初始化磁盘分配表初始化打开文件表输入命令分析命令命令表中有该命令?无显示:命令帮助创建删除读取显示重命名写入查询列表关闭执行命令执行命令退出程序(exit)各个模块的具体实现:(包含流程图和代码)(1) .建立文件:create(文件名,记录长度)模拟文件系统进行“建立文件”的处理流程如下:开始查询文件表文件表中有名字?返回有显示重命申请磁盘空间空间申请成功?显示失败否返回无在磁盘分配表中登记登记:长度=0,最大长度=申请长度,开始位置=申请节点位置 空闲情况=占用在文件表中登记登记:长度=0,最大长度=建立长度,开始位置=分配位置文件类型=txt,时间=当前时间在打开文件表中登记登记:信息和文件表中类似显示创建成功返回void fileCreate(char *fileName,int fileLength)//没有写到打开文件表{int i=0;time_t rawtime;int startPosition=0; //文件开始位置,等磁盘分配函数返回值int maxLength=fileLength;struct fileTable temp;for(i=0;i<L.size;i++)if(!strcmp(fileName,L.list[i].fileName)) //判断是否重名,如果重名直接返回{printf("文件重名,请取别的名字!\n");return ; //文件重名,退出创建函数}if(!requestDisk(&startPosition,&maxLength)){printf("申请磁盘空间失败!无法建立文件!\n");return ; //申请磁盘空间失败,退出创建函数}strcpy(temp.fileName,fileName);strcpy(temp.fileKind,"txt"); //设置文件类型为 txttemp.length=0; //创建的时候,还没写入内容,是空文件,长度设为0 temp.maxLength=fileLength; //文件的最大长度temp.start=startPosition; //文件的开始位置time(&rawtime); //获取时间temp.timeinfo=localtime(&rawtime); //把时间写到结构体里去if(!SeqListInsert(&L,L.size,temp)) //把文件插入到文件表{printf("插入文件表失败!\n");system("pause");exit(0); //把文件插入到文件表,如果失败,退出程序}printf("成功创建文件!\n\n");printf("===========================================\n");printf("文件名长度最大长度类型开始位置\n");//显示刚建立的文件printf("%s ",temp.fileName);printf("%d ",temp.length);printf("%d ",temp.maxLength);printf("%s ",temp.fileKind);printf("%d ",temp.start);printf("\n===========================================\n");printf("create进程打开了文件%s,关闭请用close命令!\n\n",fileName);//写到打开文件表strcpy(OFT[OFT_count].fileName,temp.fileName);strcpy(OFT[OFT_count].fileKind,temp.fileKind);OFT[OFT_count].length=temp.length;OFT[OFT_count].maxLength=temp.maxLength;OFT[OFT_count].start=temp.start;OFT[OFT_count].openCount=1;OFT[OFT_count].timeinfo=temp.timeinfo;OFT_count++; //打开表记录的是文件数//printf("count%d",OFT_count);}(2) .写文件:write(文件名,开始位置,字符串)模拟文件系统进行“建立文件”的处理流程如下:void fileWrite(char *fileName,int position,char *s)//找到文件,写到打开表,根据打开表操作{int i=0;int len=0; //计算写入字串长度,跟原来长度相加,如果超过最大长度,就失败int k=0; //如果在打开表里打到记录,则记录位置int flag=0; //如果flag=1,说明在打开表里找到了,不用在文件表里找了len=strlen(s);for(i=0;i<OFT_count;i++){if(!strcmp(fileName,OFT[i].fileName)){k=i;flag=1;OFT[i].openCount++;//多个进程打开,计算器加1break;}}if(flag!=1) //文件不在打开表,找到它,并写到打开表最后{for(i=0;i<L.size;i++){if(!strcmp(fileName,L.list[i].fileName)) //找到文件,写到文件打开表的最后{strcpy(OFT[OFT_count].fileName,L.list[i].fileName);strcpy(OFT[OFT_count].fileKind,L.list[i].fileKind);OFT[OFT_count].length=L.list[i].length;OFT[OFT_count].maxLength=L.list[i].maxLength;OFT[OFT_count].start=L.list[i].start;OFT[OFT_count].timeinfo=L.list[i].timeinfo;OFT[OFT_count].openCount++;k=OFT_count; //记录在文件打开表中的位置flag=1; //标志在打开文件表里}}}if(1==flag) //如果在打开表里找到文件,则不用再找文件表{if(OFT[k].length+len>OFT[k].maxLength){printf("超过文件最大长度,写入失败!\n");return ;}else if(position<0||position>OFT[k].length){printf("插入位置非法!请检查参数\n");return ;}else{int j=0;for(i=OFT[k].length-1;i>=OFT[k].start+position;i--)disk[i+len]=disk[i]; //给插入的字符串空出位置for(i=OFT[k].start+position;i<OFT[k].start+position+len;i++,j++)disk[i]=s[j]; //写进磁盘for(i=0;i<L.size;i++) //改变文件长度{if(!strcmp(fileName,L.list[i].fileName)){L.list[i].length=L.list[i].length+len; //设置文件长度break;}}OFT[k].length=OFT[k].length+len; //同时更新打开文件表中文件的长度printf("成功写入!\n");printf("write进程打开了文件%s,关闭请用close命令!\n\n",fileName);}}elseprintf("无此文件,请输入正确的文件名!");}(3) .读文件:read (文件名,开始位置,长度)模拟文件系统进行“读取文件”的处理流程如下:开始查询打开文件表查询文件表在打开文件表里?不在在文件表里?显示无文件返回不在写进模拟磁盘在在读取文件记录write 参数合法?合法显示成功返回显示参数非法非法v oid fileRead(char *fileName,int position,int length){ int i; int flag=0; int k=0;for(i=0;i<OFT_count;i++) //查找文件打开表,如果存在,则不需要再查找文件表 {if(!strcmp(fileName,OFT[i].fileName))开始查询文件表在打开文件表里?不在在文件表里?显示无文件返回不在在在读取文件记录read 参数合法?非法显示参数非法返回根据参数读取模拟磁盘里的记录返回合法{k=i;flag=1;OFT[i].openCount++;//多个进程打开,计算器加1break;}}if(flag!=1) //文件不在打开表,找到它,并写到打开表最后{for(i=0;i<L.size;i++){if(!strcmp(fileName,L.list[i].fileName)) //找到文件,写到文件打开表{strcpy(OFT[OFT_count].fileName,L.list[i].fileName);strcpy(OFT[OFT_count].fileKind,L.list[i].fileKind);OFT[OFT_count].length=L.list[i].length;OFT[OFT_count].maxLength=L.list[i].maxLength;OFT[OFT_count].start=L.list[i].start;OFT[OFT_count].timeinfo=L.list[i].timeinfo;OFT[OFT_count].openCount++;k=OFT_count;//OFT_count=1;//初次打开,赋值为1flag=1; //标志在打开文件表里}}}if(flag==1){if(position<0||position+length>OFT[k].length){printf("读取参数错误,请检查参数!\n");return ;}for(i=0;i<length;i++)printf("%c",disk[OFT[k].start+position+i-1]); //读取内容printf("\nread进程打开了文件%s,关闭请用close命令!\n\n",fileName);}}}(4) .显示文件所有内容 type(文件名)和read方法类似,只不过是在参数上显示文件所有内容,故不再重复画流程图void fileType(char *fileName){int i;int flag=0;int k=0;for(i=0;i<OFT_count;i++){if(!strcmp(fileName,OFT[i].fileName)){k=i;flag=1;OFT[i].openCount++;//多个进程打开,计算器加1break;}}if(flag!=1) //文件不在打开表,找到它,并写到打开表最后{for(i=0;i<L.size;i++){if(!strcmp(fileName,L.list[i].fileName)) //找到文件,写到文件打开表{strcmp(OFT[OFT_count].fileName,L.list[i].fileName);strcmp(OFT[OFT_count].fileKind,L.list[i].fileKind);OFT[OFT_count].length=L.list[i].length;OFT[OFT_count].maxLength=L.list[i].maxLength;OFT[OFT_count].start=L.list[i].start;OFT[OFT_count].timeinfo=L.list[i].timeinfo;OFT[OFT_count].openCount++;k=OFT_count;//OFT_count=1;//初次打开,赋值为1flag=1; //标志在打开文件表里}}}if(flag==1){for(i=0;i<OFT[k].length;i++)printf("%c",disk[OFT[k].start+i]); //显示全部内容if(OFT[k].length==0)printf("文件为空,无内容显示!\n");printf("\n===========================================\n");printf("\ncreate进程打开了文件%s,关闭请用close命令!\n\n",fileName);// printf(",,,,\n");// printf("OFT[k].length %d\n",OFT[k].length);}elseprintf("无此文件,请检查文件名!\n");}(5).删除文件delete(文件名):void fileDel(char *fileName){int i;int flag=0;int k=0; //记录文件在文件表中的位置SLNode *p; //磁盘空间分配表指针SeqDataType x; //存储被删除的结点,无特殊意义for(i=0;i<OFT_count;i++) //判断是否被别的进程占用,若被占用,打印出错,直接返回 if(!strcmp(fileName,OFT[i].fileName)){printf("别的进程占用文件!无法删除!");return ;}for(i=0;i<L.size;i++)//从文件表里查找到要删除的文件,若查找不到,直接返回{if(!strcmp(fileName,L.list[i].fileName)){flag=1; k=i; break;}}if(flag==0){printf("无此文件!");return ;}if(flag==1)//查找到文件后,把磁盘空间置为空闲,之后从文件表中删除{for(p=freeDiskTableHead;p->next!=NULL;p=p->next){if(p->next->data.start==L.list[k].start){p->next->eFlag=0;printf("成功删除!\n");break;}}SeqListDelete(&L,k,&x);//从文件表中删除}}开始查询打开文件表显示被进程占用无法删除在打开文件表里?在不在在查询文件表返回在文件表里?显示无此文件返回不在删除该文件节点定位该文件在磁盘分配表中的节点,置标志为空闲删除打开文件表中该文件条目返回显示删除成功(6) .重命名文件ren(文件名,新文件名)模拟文件系统进行“重命名文件”的处理流程如下:void fileRen(char *fileName,char *newName) {int i=0;返回返回显示重命名成功返回给文件赋新名不在显示无此文件在文件表里?查询文件表在不在在在打开文件表里?显示被进程占用无法重命名查询打开文件表开始int flag=0;for(i=0;i<OFT_count;i++) //若还有别的进程打开文件,刚不能重命名if(!strcmp(fileName,OFT[i].fileName)){printf("别的进程占用文件!无法重命名!\n");return ;}for(i=0;i<L.size;i++) //在文件表里找到,并重命名if(!strcmp(fileName,L.list[i].fileName)){strcpy(L.list[i].fileName,newName);flag=1;break;}if(flag==1)printf("重命名成功!\n");elseprintf("重命名失败!无此文件\n");}(7) .查询文件属性ask(文件名)模拟文件系统进行“查询文件属性”的处理流程如下:void fileAsk(char *fileName){int i; int flag=0;for(i=0;i<OFT_count;i++) //如果在打开表里找到文件,则不用再找文件表{if(!strcmp(fileName,OFT[i].fileName)){printf("文件名:%s\n",OFT[i].fileName);printf("类型:%s\n",OFT[i].fileKind);printf("长度:%d\n",OFT[i].length);printf("打开进程数:%d\n",OFT[i].openCount);printf("创建时间:%s\n",asctime(OFT[i].timeinfo));flag=1;break;}}if(flag!=1){for(i=0;i<L.size;i++) //从文件表里查找文件{if(!strcmp(fileName,L.list[i].fileName)){printf("文件名:%s\n",L.list[i].fileName); printf("类型:%s\n",L.list[i].fileKind); printf("长度:%d\n",L.list[i].length);printf("创建时间:%s\n",asctime(L.list[i].timeinfo)); flag=1;break; } } }if(flag==0)printf("无此文件!\n");}开始查询打开文件表显示文件属性文件名,类型,长度打开进程数 创建时间在打开文件表里?在不在返回查询文件表在文件表里?显示无此文件返回不在显示文件属性文件名,类型,长度,创建时间返回在(8) .关闭文件close(文件名)模拟文件系统进行“关闭文件”的处理流程如下:void fileClose(char *fileName) {int i;int flag=0;开始查询打开文件表显示此文件没有被打开在打开文件表里?不在在返回文件打开数openCount=0?显示:计数器减1大于0删除打开文件表中该文件条目显示删除成功返回返回int j;for(i=0;i<OFT_count;i++){if(!strcmp(fileName,OFT[i].fileName)) //在文件打开表里找到,把打开数减1,//如果计数为0,显示关闭成功!{OFT[i].openCount--;flag=1;if(OFT[i].openCount==0){for(j=i;j<OFT_count;j++)OFT[j]=OFT[j+1]; //删除要关闭的文件OFT_count--;printf("成功关闭文件!\n");}elseprintf("计数器减1\n");break;}}if(flag==0)printf("此文件没有打开!\n");}四程序的调试与测试1.程序主界面2.输入create ?,显示命令的帮助3.创建一个长度为2000的文件 create what 2000显示创建文件成功,并显示刚创建的文件信息还有友情提示,create进程打开了文件what,需要用 close命令关闭4.往文件里写入内容 write what 0 welcome!显示成功写入,用type命令显示刚写入的内容,显示正确5.继续从中间写入内容write what 3 test,之后用type命令显示内容,能得到正确结果6.关闭文件 close what当计数器为0,显示成功关闭文件,结果比较满意7.读文件 read what 3 4读出来 test字符串,结果正确8.查询文件属性 ask what显示了what文件的属性,结果正确,测试成功!对于测试用例,还有很多路径都有测试过,鉴于篇幅,就不再列出所有可能的路径来进行白盒测试。