操作系统课程设计 简单文件系统的实现Word格式.docx
《操作系统课程设计 简单文件系统的实现Word格式.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计 简单文件系统的实现Word格式.docx(46页珍藏版)》请在冰豆网上搜索。
用于读文件。
●my_rm:
用于删除文件。
●my_exitsys:
用于退出文件系统。
2、设计思路(主要算法描述、程序流程图等):
1.系统主函数main()
(1)对应命令:
无
(2)命令调用格式:
(3)函数设计格式:
voidmain()
(4)功能:
系统主函数
(5)输入:
(6)输出:
(7)函数需完成的工作:
①对前面定义的全局变量进行初始化;
②调用startsys()进入文件系统;
③列出文件系统提供的各项功能及命令调用格式;
④显示命令行提示符,等待用户输入命令;
⑤将用户输入的命令保存到一个buf中;
⑥对buf中的内容进行命令解析,并调用相应的函数执行用户键入的命令;
⑦如果命令不是“my_exitsys”,则命令执行完毕后转④。
2.进入文件系统函数startsys()
voidstartsys()
由main()函数调用,进入并初始化我们所建立的文件系统,以供用户使用。
无
无。
①申请虚拟磁盘空间;
②使用c语言的库函数fopen()打开myfsys文件:
若文件存在,则转③;
若文件不存在,则创建之,转⑤
③使用c语言的库函数fread()读入myfsys文件内容到用户空间中的一个缓冲区中,并判断其开始的8个字节内容是否为“”(文件系统魔数),如果是,则转④;
否则转⑤;
④将上述缓冲区中的内容复制到内存中的虚拟磁盘空间中;
转⑦
⑤在屏幕上显示“myfsys文件系统不存在,现在开始创建文件系统”信息,并调用my_format()对①中申请到的虚拟磁盘空间进行格式化操作。
转⑥;
⑥将虚拟磁盘中的内容保存到myfsys文件中;
⑦使用c语言的库函数fclose()关闭myfsys文件;
⑧初始化用户打开文件表,将表项0分配给根目录文件使用,并填写根目录文件的相关信息,由于根目录没有上级目录,所以表项中的dirno和diroff分别置为5(根目录所在起始块号)和0;
并将ptrcurdir指针指向该用户打开文件表项。
⑨将当前目录设置为根目录。
3.磁盘格式化函数my_format()
my_format
voidmy_format()
对虚拟磁盘进行格式化,布局虚拟磁盘,建立根目录文件(或根目录区)。
①将虚拟磁盘第一个块作为引导块,开始的8个字节是文件系统的魔数,记为“”;
在之后写入文件系统的描述信息,如FAT表大小及位置、根目录大小及位置、盘块大小、盘块数量、数据区开始位置等信息;
②在引导块后建立两张完全一样的FAT表,用于记录文件所占据的磁盘块及管理虚拟磁盘块的分配,每个FAT占据两个磁盘块;
对于每个FAT中,前面5个块设置为已分配,后面995个块设置为空闲;
③在第二张FAT后创建根目录文件root,将数据区的第1块(即虚拟磁盘的第6块)分配给根目录文件,在该磁盘上创建两个特殊的目录项:
“.”和“..”,其内容除了文件名不同之外,其他字段完全相同。
4.更改当前目录函数my_cd()
(1)对应命令:
my_cd
my_cddirname
voidmy_cd(char*dirname)
改变当前目录到指定的名为dirname的目录。
dirname:
新的当前目录的目录名;
①调用my_open()打开指定目录名的父目录文件,并调用do_read()读入该父目录文件内容到内存中;
②在父目录文件中检查新的当前目录名是否存在,如果存在则转③,否则返回,并显示出错信息;
③调用my_close()关闭①中打开的父目录文件;
④调用my_close()关闭原当前目录文件;
⑤如果新的当前目录文件没有打开,则打开该目录文件;
并将ptrcurdir指向该打开文件表项;
⑥设置当前目录为该目录。
5.创建子目录函数my_mkdir()
my_mkdir
my_mkdirdirname
voidmy_mkdir(char*dirname)
在当前目录下创建名为dirname的子目录。
新建目录的目录名。
①调用do_read()读入当前目录文件内容到内存,检查当前目录下新建目录文件是否重名,若重名则返回,并显示错误信息;
②为新建子目录文件分配一个空闲打开文件表项,如果没有空闲表项则返回-1,并显示错误信息;
③检查FAT是否有空闲的盘块,如有则为新建目录文件分配一个盘块,否则释放①中分配的打开文件表项,返回,并显示错误信息;
④在当前目录中为新建目录文件寻找一个空闲的目录项或为其追加一个新的目录项;
需修改当前目录文件的长度信息,并将当前目录文件的用户打开文件表项中的fcbstate置为1;
⑤准备好新建目录文件的FCB的内容,文件的属性为目录文件,以覆盖写方式调用do_write()将其填写到对应的空目录项中;
⑥在新建目录文件所分配到的磁盘块中建立两个特殊的目录项“.”和“..”目录项,方法是:
首先在用户空间中准备好内容,然后以截断写或者覆盖写方式调用do_write()将其写到③中分配到的磁盘块中;
⑦返回。
6.删除子目录函数rmdir()
my_rmdir
my_rmdirdirname
(1)函数设计格式:
voidmy_rmdir(char*dirname)
(2)功能:
在当前目录下删除名为dirname的子目录。
(3)输入:
欲删除目录的目录名。
(4)输出:
(5)函数需完成的工作:
①调用do_read()读入当前目录文件内容到内存,检查当前目录下欲删除目录文件是否存在,若不存在则返回,并显示错误信息;
②检查欲删除目录文件是否为空(除了“.”和“..”外没有其他子目录和文件),可根据其目录项中记录的文件长度来判断,若不为空则返回,并显示错误信息;
③检查该目录文件是否已经打开,若已打开则调用my_close()关闭掉;
④回收该目录文件所占据的磁盘块,修改FAT;
⑤从当前目录文件中清空该目录文件的目录项,且free字段置为0:
以覆盖写方式调用do_write()来实现;
⑥修改当前目录文件的用户打开表项中的长度信息,并将表项中的fcbstate置为1;
7.显示目录函数my_ls()
my_ls
voidmy_ls(void)
显示当前目录的内容(子目录和文件信息)。
①调用do_read()读出当前目录文件内容到内存;
②将读出的目录文件的信息按照一定的格式显示到屏幕上;
③返回。
8.创建文件函数my_create()
my_create
my_createfilename
intmy_create(char*filename)
创建名为filename的新文件。
filename:
新建文件的文件名,可能包含路径。
若创建成功,返回该文件的文件描述符(文件打开表中的数组下标);
否则返回-1。
①为新文件分配一个空闲打开文件表项,如果没有空闲表项则返回-1,并显示错误信息;
②若新文件的父目录文件还没有打开,则调用my_open()打开;
若打开失败,则释放①中为新建文件分配的空闲文件打开表项,返回-1,并显示错误信息;
③调用do_read()读出该父目录文件内容到内存,检查该目录下新文件是否重名,若重名则释放①中分配的打开文件表项,并调用my_close()关闭②中打开的目录文件;
然后返回-1,并显示错误信息;
④检查FAT是否有空闲的盘块,如有则为新文件分配一个盘块,否则释放①中分配的打开文件表项,并调用my_close()关闭②中打开的目录文件;
返回-1,并显示错误信息;
⑤在父目录中为新文件寻找一个空闲的目录项或为其追加一个新的目录项;
需修改该目录文件的长度信息,并将该目录文件的用户打开文件表项中的fcbstate置为1;
⑥准备好新文件的FCB的内容,文件的属性为数据文件,长度为0,以覆盖写方式调用do_write()将其填写到⑤中分配到的空目录项中;
⑦为新文件填写①中分配到的空闲打开文件表项,fcbstate字段值为0,读写指针值为0;
⑧调用my_close()关闭②中打开的父目录文件;
⑨将新文件的打开文件表项序号作为其文件描述符返回。
9.删除文件函数my_rm()
my_rm
my_rmfilename
voidmy_rm(char*filename)
删除名为filename的文件。
欲删除文件的文件名,可能还包含路径。
①若欲删除文件的父目录文件还没有打开,则调用my_open()打开;
若打开失败,则返回,并显示错误信息;
②调用do_read()读出该父目录文件内容到内存,检查该目录下欲删除文件是否存在,若不存在则返回,并显示错误信息;
③检查该文件是否已经打开,若已打开则关闭掉;
④回收该文件所占据的磁盘块,修改FAT;
⑤从文件的父目录文件中清空该文件的目录项,且free字段置为0:
;
⑥修改该父目录文件的用户打开文件表项中的长度信息,并将该表项中的fcbstate置为1;
10.打开文件函数my_open()
my_open
my_openfilename
intmy_open(char*filename)
打开当前目录下名为filename的文件。
欲打开文件的文件名
若打开成功,返回该文件的描述符(在用户打开文件表中表项序号);
①检查该文件是否已经打开,若已打开则返回-1,并显示错误信息;
②调用do_read()读出父目录文件的内容到内存,检查该目录下欲打开文件是否存在,若不存在则返回-1,并显示错误信息;
③检查用户打开文件表中是否有空表项,若有则为欲打开文件分配一个空表项,若没有则返回-1,并显示错误信息;
④为该文件填写空白用户打开文件表表项内容,读写指针置为0;
⑤将该文件所分配到的空白用户打开文件表表项序号(数组下标)作为文件描述符fd返回。
11.关闭文件函数my_close()
my_close
my_closefd
voidmy_close(intfd)
关闭前面由my_open()打开的文件描述符为fd的文件。
fd:
文件描述符。
①检查fd的有效性(fd不能超出用户打开文件表所在数组的最大下标),如果无效则返回-1;
②检查用户打开文件表表项中的fcbstate字段的值,如果为1则需要将该文件的FCB的内容保存到虚拟磁盘上该文件的目录项中,方法是:
打开该文件的父目录文件,以覆盖写方式调用do_write()将欲关闭文件的FCB写入父目录文件的相应盘块中;
③回收该文件占据的用户打开文件表表项(进行清空操作),并将topenfile字段置为0;
④返回。
12.写文件函数my_write()
my_write
my_writefd
intmy_write(intfd)
将用户通过键盘输入的内容写到fd所指定的文件中。
磁盘文件的读写操作都必须以完整的数据块为单位进行,在写操作时,先将数据写在缓冲区中,缓冲区的大小与磁盘块的大小相同,然后再将缓冲区中的数据一次性写到磁盘块中;
读出时先将一个磁盘块中的内容读到缓冲区中,然后再传送到用户区。
本实例为了简便起见,没有设置缓冲区管理,只是在读写文件时由用户使用malloc()申请一块空间作为缓冲区,读写操作结束后使用free()释放掉。
写操作常有三种方式:
截断写、覆盖写和追加写。
截断写是放弃原来文件的内容,重新写文件;
覆盖写是修改文件在当前读写指针所指的位置开始的部分内容;
追加写是在原文件的最后添加新的内容。
在本实例中,输入写文件命令后,系统会出现提示让用户选择其中的一种写方式,并将随后键盘输入的内容按照所选的方式写到文件中,键盘输入内容通过CTR+Z键(或其他设定的键)结束。
open()函数的返回值,文件的描述符;
实际写入的字节数。
①检查fd的有效性(fd不能超出用户打开文件表所在数组的最大下标),如果无效则返回-1,并显示出错信息;
②提示并等待用户输入写方式:
(1:
截断写;
2:
覆盖写;
3:
追加写)
③如果用户要求的写方式是截断写,则释放文件除第一块外的其他磁盘空间内容(查找并修改FAT表),将内存用户打开文件表项中文件长度修改为0,将读写指针置为0并转④;
如果用户要求的写方式是追加写,则修改文件的当前读写指针位置到文件的末尾,并转④;
如果写方式是覆盖写,则直接转④;
④提示用户:
整个输入内容通过CTR+Z键(或其他设定的键)结束;
用户可分多次输入写入内容,每次用回车结束;
⑤等待用户从键盘输入文件内容,并将用户的本次输入内容保存到一临时变量text[]中,要求每次输入以回车结束,全部结束用CTR+Z键(或其他设定的键);
⑥调用do_write()函数将通过键盘键入的内容写到文件中。
⑦如果do_write()函数的返回值为非负值,则将实际写入字节数增加do_write()函数返回值,否则显示出错信息,并转⑨;
⑧如果text[]中最后一个字符不是结束字符CTR+Z,则转⑦继续进行写操作;
否则转⑨;
⑨如果当前读写指针位置大于用户打开文件表项中的文件长度,则修改打开文件表项中的文件长度信息,并将fcbstate置1;
⑩返回实际写入的字节数。
13.实际写文件函数do_write()
intmy_write(intfd,char*text,intlen,charwstyle)
被写文件函数my_write()调用,用来将键盘输入的内容写到相应的文件中去。
text:
指向要写入的内容的指针;
len:
本次要求写入字节数
wstyle:
写方式
①用malloc()申请1024B的内存空间作为读写磁盘的缓冲区buf,申请失败则返回-1,并显示出错信息;
②将读写指针转化为逻辑块块号和块内偏移off,并利用打开文件表表项中的首块号及FAT表的相关内容将逻辑块块号转换成对应的磁盘块块号blkno;
如果找不到对应的磁盘块,则需要检索FAT为该逻辑块分配一新的磁盘块,并将对应的磁盘块块号blkno登记到FAT中,若分配失败,则返回-1,并显示出错信息;
③如果是覆盖写,或者如果当前读写指针所对应的块内偏移off不等于0,则将块号为blkno的虚拟磁盘块全部1024B的内容读到缓冲区buf中;
否则便用ASCII码0清空buf;
④将text中未写入的内容暂存到缓冲区buff的第off字节开始的位置,直到缓冲区满,或者接收到结束字符CTR+Z为止;
将本次写入字节数记录到tmplen中;
⑤将buf中1024B的内容写入到块号为blkno的虚拟磁盘块中;
⑥将当前读写指针修改为原来的值加上tmplen;
并将本次实际写入的字节数增加tmplen;
⑦如果tmplen小于len,则转②继续写入;
否则转⑧;
⑧返回本次实际写入的字节数。
14.读文件函数my_read()
my_read
my_readfdlen
intmyread(intfd,intlen)
读出指定文件中从读写指针开始的长度为len的内容到用户空间中。
len:
要从文件中读出的字节数。
实际读出的字节数。
①定义一个字符型数组text[len],用来接收用户从文件中读出的文件内容;
②检查fd的有效性(fd不能超出用户打开文件表所在数组的最大下标),如果无效则返回-1,并显示出错信息;
③调用do_read()将指定文件中的len字节内容读出到text[]中;
④如果do_read()的返回值为负,则显示出错信息;
否则将text[]中的内容显示到屏幕上;
⑤返回。
15.实际读文件函数do_read()
intdo_read(intfd,intlen,char*text)
被my_read()调用,读出指定文件中从读写指针开始的长度为len的内容到用户空间的text中。
要求从文件中读出的字节数。
指向存放读出数据的用户区地址
①使用malloc()申请1024B空间作为缓冲区buf,申请失败则返回-1,并显示出错信息;
②将读写指针转化为逻辑块块号及块内偏移量off,利用打开文件表表项中的首块号查找FAT表,找到该逻辑块所在的磁盘块块号;
将该磁盘块块号转化为虚拟磁盘上的内存位置;
③将该内存位置开始的1024B(一个磁盘块)内容读入buf中;
④比较buf中从偏移量off开始的剩余字节数是否大于等于应读写的字节数len,如果是,则将从off开始的buf中的len长度的内容读入到text[]中;
否则,将从off开始的buf中的剩余内容读入到text[]中;
⑤将读写指针增加④中已读字节数,将应读写的字节数len减去④中已读字节数,若len大于0,则转②;
否则转⑥;
⑥使用free()释放①中申请的buf。
⑦返回实际读出的字节数。
16.退出文件系统函数my_exitsys()
my_exitsys
voidmy_exitsys()
退出文件系统。
①使用C库函数fopen()打开磁盘上的myfsys文件;
②将虚拟磁盘空间中的所有内容保存到磁盘上的myfsys文件中;
③使用c语言的库函数fclose()关闭myfsys文件;
④撤销用户打开文件表,释放其内存空间
⑤释放虚拟磁盘空间。
程序启动
流程图
加载文件系统
是
否
创建文件系统,并格式化
等待用户命令输入
……
3、程序实现代码:
#include<
stdio.h>
stdlib.h>
string.h>
time.h>
#defineBLOCKSIZE1024//磁盘块大小
#defineSIZE1024000//虚拟磁盘空间大小
#defineEND65535//FAT中的文件结束标志
#defineFREE0//FAT中盘块空闲标志
#defineROOTBLOCKNUM2//根目录区所占盘块数
#defineMAXOPENFILE10//最多同时打开文件个数t
#defineMAXTEXT10000
/*文件控制块*/
typedefstructFCB{
charfilename[8];
//文件名
charexname[3];
//文件扩展名
unsignedcharattribute;
//文件属性字段,值为0时表示目录文件,值为1时表示数据文件
unsignedshorttime;
//文件创建时间
unsignedshortdate;
//文件创建日期
unsignedshortfirst;
//文件起始盘块号
unsignedlonglength;
//文件长度
charfree;
//表示目录项是否为空,若值为0,表示空,值为1,表示已分配
}fcb;
/*文件分配表*/
typedefstructFAT
{
unsignedshortid;
//磁盘块的状态(空闲的,最后的,下一个)
}fat;
/*用户打开文件表*/
typedefstructUSEROPEN
unsignedlong