操作系统课程设计报告
专业:
班级:
姓名:
学号:
老师:
简单文件系统的实现
1
如文档对您有帮助,欢迎下载支持,谢谢!
一、课程设计的目的
1. 通过具体的文件存储空间的管理、文件的物理结构、目录结构和文件操作的实现,加深对文件系统内部数据结构、功能以及实现过程的理解。 二、 课程设计要求
1. 在内存中开辟一个虚拟磁盘空间作为文件存储分区,在其上实现一个简单的基于多级目录的单用户单任务系统中的文件系统。在退出该文件系统的使用时,应将该虚拟文件系统以一个Windows 文件的方式保存到磁盘上,以便下次可以再将它恢复到内存的虚拟磁盘空间中。 2文件存储空间的分配可采用显式链接分配或其他的办法。
3空闲磁盘空间的管理可选择位示图或其他的办法。如果采用位示图来管理文件存储空间,并采用显式链接分配方式,那么可以将位示图合并到FAT中。
文件目录结构采用多级目录结构。为了简单起见,可以不使用索引结点,其中的每个目录项应包含文件名、物理地址、长度等信息,还可以通过目录项实现对文件的读和写的保护。 要求提供以下有关的操作命令:
my_format:对文件存储器进行格式化,即按照文件系统的结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。 my_mkdir:用于创建子目录。 my_rmdir:用于删除子目录。 my_ls:用于显示目录中的内容。 my_cd:用于更改当前目录。 my_create:用于创建文件。 my_open:用于打开文件。 my_close:用于关闭文件。 my_write:用于写文件。 my_read:用于读文件。 my_rm:用于删除文件。
my_exitsys:用于退出文件系统。 三、程序的设计细想和框图 1.打开文件函数fopen()
(1)格式:FILE *fopen(const char *filename,const char *mode) (2)功能:按照指定打开方式打开指定文件。 (3)输入参数说明:
filename:待打开的文件名,如果不存在就创建该文件。 mode: 文件打开方式,常用的有:
\"r\":为读而打开文本文件(不存在则出错)。
\"w\":为写而打开文本文件(若不存在则创建该文件;反之,则从文件起始位置写,原内容将被覆盖)。
\"a\":为在文件末尾添加数据而打开文本文件。(若不存在则创建该文件;反之,在原文件末尾追加)。
\"r+\":为读和写而打开文本文件。(读时,从头开始;在写数据时,新数据只覆盖所占的空间,其后不变) 。
\"w+\":首先建立一个新文件,进行写操作,随后可以从头开始读。(若文件存在,原内容将全部消失) 。
\"a+\":功能与\"a\"相同;只是在文件末尾添加新的数据后,可以从头开始读。
另外,上述模式字符串中都可以加一个“b”字符,如rb、wb、ab、rb+、wb+、ab+等组合,
2
如文档对您有帮助,欢迎下载支持,谢谢!
字符“b”表示fopen() 函数打开的文件为二进制文件,而非纯文字文件。 (4)输出:一个指向FILE类型的指针。 2.关闭文件函数fclose()
(1)格式:int fclose(FILE * stream);
(2)功能:用来关闭先前fopen()打开的一个文件。此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。 (3)输入参数说明:
stream:指向要关闭文件的指针,它是先前执行fopen()函数的返回值。
(4)输出:若关闭文件成功则返回0;有错误发生时则返回EOF并把错误代码存到errno。 3.读文件函数fread()
(1)格式:size_t fread( void *buffer, size_t size, size_t count, FILE *stream ); (2)功能:读二进制文件到内存。 (3)输入参数说明:
buffer:用于存放输入数据的缓冲区的首地址;
stream:使用fopen()打开的文件的指针,用于指示要读取的文件; size: 每个数据块的字节数; count: 要读入的数据块的个数; size*count:表示要求读取的字节数。 (4)输出:实际读取的数据块的个数。 4.写文件函数fwrite()
(1)格式:size_t fwite(const void *buffer,size_t size,size_t count,FILE *stream); (2)功能:将数据写到二进制文件中。 (3)输入参数说明:
buffer:用于存放输出数据的缓冲区的首地址;
stream:使用fopen()打开的文件的指针,用于指示要写出的文件; size: 每个数据块的字节数; count: 要写出的数据块的个数; size*count:表示要求写出的字符数。 (4)输出:实际写出的数据块的个数。 5.判断文件结束函数feof ()
(1)格式:int feof(FILE * stream)
(2)功能:用来判断是否已读取到文件末尾。 (3)输入参数说明:
stream:使用fopen()打开的文件的指针,用于指示要判断的文件。 (4)输出:如果已读到文件尾则返回非零值,其他情况返回0。 6 主要函数功能实现:
int format(); // 格式化磁盘
int mkdir(char *sonfname); // 创建子目录 int rmdir(char *sonfname); // 删除子目录 int create(char *name); // 创建文件 int listshow();// 显示子文件信息 int delfile(char *name); //删除文件
int changePath(char *sonfname);// 更改当前路径 int write(char *name); // 写入文件
3
如文档对您有帮助,欢迎下载支持,谢谢!
int exit();//退出系统
int open(char *file);//打开文件 int close(char *file);// 关闭文件 int read(char *file);//读取文件 7 主要的框架
四、程序实现和程序调试遇到的问题的分析
1 对于DOS的文件操作使用不熟悉,经常输入错误命令 2调试的时候跟踪变量的时候,难以锁定实际的变量是什么
3 对于文件的存储结构不熟悉,在构造FAT的时候不知如何解决,查阅了大量的资料和跟老师交流才慢慢开始理解
4由于买的实验册对于文件的介绍过于简单,导致理解上出现很大的困难。 五、结果分析和总结
1基本上实现了DOS下简单文件系统的实现,通过学习基本掌握了文件系统的存储结构 2当遇到困难的时候通过认真思考很查阅资料很大问题都是可以自己解决的。通过这次实验锻炼了自己的动手的能力和分析问题的能力
3在构造函数的时候可以开阔思维同时加深自己对文件系统实现的理解 4通过这样的实验开始对DOS的环境文件命令输入有了初步的理解 5通过跟老师的讨论解决自己心中的疑惑 六、程序
#include #define GENERAL 1//1代表普通文件2代表目录文件0表示空文件 #define DIRECTORY 2 #define Zero 0 struct FCB { char fname[16]; //文件名 char type; // 0空文件 1目录文件 2空文件 int size; //文件大小 int fatherBlockNum; //当前的父目录盘块号 int currentBlockNum; //当前的盘块 void initialize() { strcpy(fname,\"\\0\"); type = Zero; size =0; fatherBlockNum = currentBlockNum = 0; } 4 如文档对您有帮助,欢迎下载支持,谢谢! }; const char* FilePath = \"C:\\\\myfiles\";/*常量设置*/ const int BlockSize = 512; //盘块大小 const int OPEN_MAX = 5; //能打开最多的文件数 const int BlockCount = 128; //盘块数 const int DiskSize = BlockSize * BlockCount; //磁盘大小 const int BlockFcbCount = BlockSize/sizeof(FCB);//目录文件的最多FCB数 int OpenFileCount = 0; // 统计当前打开文件数目 struct OPENLIST //用户文件打开表 { int files; //当前打开文件数 FCB f[OPEN_MAX]; //FCB拷贝 OPENLIST() { files=0; for(int i=0;i DISK/**********************************************************************/ 5 如文档对您有帮助,欢迎下载支持,谢谢! { int FAT1[BlockCount]; //FAT1 int FAT2[BlockCount]; //FAT2 struct dirFile root; //根目录 char data[BlockCount-3][BlockSize]; void format(){ memset(FAT1,0,BlockCount); //FAT1 memset(FAT2,0,BlockCount); //FAT2 FAT1[0]=FAT1[1]=FAT1[2]=-2; //0,1,2盘块号依次代表FAT1,FAT2,根目录区 FAT2[0]=FAT2[1]=FAT2[2]=-2; //FAT作备份 root.init(2,2,\"C:\\\\\");//根目录区 memset(data,0,sizeof(data));//数据区 } }; FILE *fp; //磁盘文件地址 char * BaseAddr; //虚拟磁盘空间基地址 string currentPath=\"C:\\\\\"; //当前路径 int current=2; //当前目录的盘块号 string cmd; //输入指令 struct DISK *osPoint; //磁盘操作系统指针 char command[16]; //文件名标识 struct OPENLIST* openlist; //用户文件列表指针 int format(); int mkdir(char *sonfname); int rmdir(char *sonfname); int create(char *name); int listshow(); int delfile(char *name); int changePath(char *sonfname); int write(char *name); int exit(); int open(char *file); int close(char *file); int read(char *file); /*------------初始化-----------------------*/ int format() { current = 2; currentPath=\"C:\\\\\"; //当前路径 osPoint->format();//打开文件列表初始化 delete openlist; openlist=new OPENLIST; 6 如文档对您有帮助,欢迎下载支持,谢谢! /*-------保存到磁盘上myfiles--------*/ fp = fopen(FilePath,\"w+\"); fwrite(BaseAddr,sizeof(char),DiskSize,fp); fclose(fp); printf(\"格式化成功!!\\n\"); return 1; } int mkdir(char *sonfname)/*-----------------------创建子目录-------------------*/ {//判断是否有重名寻找空白子目录项寻找空白盘块号当前目录下增加该子目录项分配子目录盘块,并且初始化修改fat表 int i,temp,iFAT; struct dirFile *dir; //当前目录的指针 if(current == 2) // 根目录 dir=&(osPoint->root); else dir=(struct dirFile *)(osPoint->data [current-3]); /*--------为了避免该目录下同名文件夹--------*/ for(i = 1;i 7 如文档对您有帮助,欢迎下载支持,谢谢! /*-------------接下来进行分配----------*/ osPoint->FAT1[iFAT]=osPoint->FAT2[iFAT] = 2; //2表示分配给下级目录文件 //填写该分派新的盘块的参数 strcpy(dir->fcb[temp].fname,sonfname); dir->fcb[temp].type=DIRECTORY; dir->fcb[temp].fatherBlockNum=current; dir->fcb[temp].currentBlockNum=iFAT; //初始化子目录文件盘块 dir=(struct dirFile*)(osPoint->data [iFAT-3]); //定位到子目录盘块号 dir->init (current,iFAT,sonfname);//iFAT是要分配的块号,这里的current用来指要分配的块的父块号 printf(\"创建子目录成功!\\n\"); return 1; } int rmdir(char *sonfname)/*-------删除当前目录下的文件夹--------*/ { int i,temp,j;//确保当前目录下有该文件,并记录下该FCB下标 struct dirFile *dir; //当前目录的指针 if(current==2) dir=&(osPoint->root); else dir=(struct dirFile *)(osPoint->data [current-3]); for(i=1;i 如文档对您有帮助,欢迎下载支持,谢谢! if(sonDir->fcb[i].type!=Zero) { printf(\"该文件夹为非空文件夹,为确保安全,请清空后再删除!\\n\"); return 0; } } /*开始删除子目录操作*/ osPoint->FAT1[j] = osPoint->FAT2[j]=0; //fat清空 char *p=osPoint->data[j-3]; //格式化子目录 memset(p,0,BlockSize); dir->fcb[temp].initialize(); //回收子目录占据目录项 printf(\"删除当前目录下的文件夹成功\\n\"); return 1; } /*-----------在当前目录下创建文本文件---------------*/ int create(char *name){ int i,iFAT;//temp, int emptyNum = 0,isFound = 0; //空闲目录项个数 struct dirFile *dir; //当前目录的指针 if(current==2) dir=&(osPoint->root); else dir=(struct dirFile *)(osPoint->data [current-3]); for(i=1;i 9 如文档对您有帮助,欢迎下载支持,谢谢! break; } if(i==BlockCount){ printf(\"磁盘已满!\\n\"); return 0; } iFAT=i; /*------进入分配阶段---------*///分配磁盘块 osPoint->FAT1[iFAT] = osPoint->FAT2[iFAT] = 1; /*-----------接下来进行分配----------*///填写该分派新的盘块的参数 strcpy(dir->fcb[emptyNum].fname,name); dir->fcb[emptyNum].type=GENERAL; dir->fcb[emptyNum].fatherBlockNum=current; dir->fcb[emptyNum].currentBlockNum=iFAT; dir->fcb[emptyNum].size =0; char* p = osPoint->data[iFAT -3]; memset(p,4,BlockSize); printf(\"在当前目录下创建文本文件成功!\\n\"); return 1; } /*-------查询子目录------------*/ int listshow() { int i,DirCount=0,FileCount=0; //搜索当前目录 struct dirFile *dir; //当前目录的指针 if(current==2) dir=&(osPoint->root); else dir=(struct dirFile *)(osPoint->data [current-3]); for(i=1;i 10 如文档对您有帮助,欢迎下载支持,谢谢! return 1; } /*---------在当前目录下删除文件-----------*/ int delfile(char *name) { int i,temp,j; //确保当前目录下有该文件,并且记录下它的FCB下标 struct dirFile *dir; //当前目录的指针 if(current == 2) dir=&(osPoint->root); else dir=(struct dirFile *)(osPoint->data [current-3]); for(i=1;i < BlockFcbCount;i++) //查找该文件 { if(dir->fcb[i].type==GENERAL && strcmp(dir->fcb[i].fname,name)==0){ break; } } if(i == BlockFcbCount){ printf(\"当前目录下不存在该文件!\\n\"); return 0; } int k; for(k=0;k 11 如文档对您有帮助,欢迎下载支持,谢谢! //从打开列表中删除 /*开始删除文件操作*/ temp=i; j = dir->fcb [temp].currentBlockNum ; //查找盘块号j osPoint->FAT1[j]=osPoint->FAT2[j]=0; //fat1,fat2表标记为空白 char *p=osPoint->data[j - 3]; memset(p,0,BlockSize); //清除原文本文件的内容 dir->fcb[temp].initialize(); //type=0; //标记该目录项为空文件 printf(\"在当前目录下删除文件成功!\\n\"); return 1; } /*--------------进入当前目录下的子目录--------------*/ int changePath(char *sonfname) { struct dirFile *dir; //当前目录的指针 if(current==2) dir=&(osPoint->root); else dir=(struct dirFile *)(osPoint->data [current-3]); /*回到父目录*/ if(strcmp(sonfname,\"..\")==0){ if(current==2){ printf(\"你现已经在根目录下!\\n\"); return 0; } current = dir->fcb[0].fatherBlockNum ; currentPath = currentPath.substr(0,currentPath.size() - strlen(dir->fcb[0].fname )-1); return 1; } /*进入子目录*///确保当前目录下有该目录,并且记录下它的FCB下标 int i,temp; for(i = 1; i < BlockFcbCount; i++){ //查找该文件 if(dir->fcb[i].type==DIRECTORY&&strcmp(dir->fcb[i].fname,sonfname)==0){ temp=i; break; } } if(i==BlockFcbCount){ printf(\"不存在该目录!\\n\"); return 0; } 12 如文档对您有帮助,欢迎下载支持,谢谢! //修改当前文件信息 current=dir->fcb [temp].currentBlockNum ; currentPath = currentPath+dir->fcb [temp].fname +\"\\\\\"; printf(\"进入当前目录下的子目录成功!\\n\"); return 1; } int exit(){//保存到磁盘上C:\\myfiles //将所有文件都关闭/*--------System exit---------------------*/ fp=fopen(FilePath,\"w+\"); fwrite(BaseAddr,sizeof(char),DiskSize,fp); fclose(fp); //释放内存上的虚拟磁盘 free(osPoint); //释放用户打开文件表 delete openlist; printf(\"退出文件系统成功!\\n\\n\"); return 1; } int write(char *name)/*-------------在指定的文件里记录信息---------------*/ { int i; char *startPoint,*endPoint; //在打开文件列表中查找 file(还需要考虑同名不同目录文件的情况) for(i=0;i 13 如文档对您有帮助,欢迎下载支持,谢谢! startPoint = osPoint->data[fileStartNum]; endPoint = osPoint->data[fileStartNum + 1]; printf(\"请输入文本以Ctrl D号结束:\\"); char input; while(((input=getchar())!=4)) { if(startPoint < endPoint-1) { *startPoint++ = input; } else{ printf(\"达到单体文件最大容量!\"); *startPoint++ = 4; break; } } return 1; } int read(char *file)/*---------选择一个打开的文件读取信息----------*/ { int i,fileStartNum; char *startPoint,*endPoint; //struct dirFile *dir; //在打开文件列表中查找 file(还需要考虑同名不同目录文件的情况) for(i=0;i 14 如文档对您有帮助,欢迎下载支持,谢谢! while((*startPoint)!=4&& (startPoint < endPoint)){ putchar(*startPoint++); } printf(\"\\n\"); return 1; } int open(char *file)//打开文件/*当前目录下添加一个打开文件*/ { int i,FcbIndex; //确保没有打开过该文件 = 相同名字 + 相同目录 for(i=0;i 15 如文档对您有帮助,欢迎下载支持,谢谢! openlist->f[OpenFileCount] = dir->fcb[FcbIndex]; //FCB拷贝 openlist->files ++; printf(\"文件打开成功!\\n\"); OpenFileCount++; return 1; } int close(char *file) { //释放该文件所占内存//释放用户打开文件列表表项 int i; //在打开文件列表中查找 file(还需要考虑同名不同目录文件的情况) for(i=0;i int main() { printf(\"@ Welcome To My Operate System Of File(FAT) @n\"); printf(\"\\n 以下是使用说明书:\\n\");//使用说明书 printf(\"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\\n\"); printf(\"@ format :对磁盘格式化. @ \\n\"); 16 如文档对您有帮助,欢迎下载支持,谢谢! printf(\"@ exit :安全退出该文件系统,保存信息. @ \\n\"); printf(\"@ mkdir dirname :创建子目录. @ \\n\"); printf(\"@ rmdir dirname :删除子目录. @ \\n\"); printf(\"@ ls dirname :显示当前目录下信息. @ \\n\"); printf(\"@ cd dirname :更改当前目录. @ \\n\"); printf(\"@ create filename :创建一个新文件,并且打开. @ \\n\"); printf(\"@ write filename :选择一个打开的文件写入信息 @ \\n\"); printf(\"@ read filename :选择一个打开的文件读取信息. @ \\n\"); printf(\"@ rm filename :删除文件. @ \\n\"); printf(\"@ open filename :打开文件. @\\n\"); printf(\"@ close filename :关闭文件. @\\n\"); printf(\"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\\n\\n\"); openlist=new OPENLIST;//创建用户文件打开表 BaseAddr=(char *)malloc(DiskSize);//申请虚拟空间并且初始化 osPoint=(struct DISK *)(BaseAddr);//虚拟磁盘初始化 if((fp=fopen(FilePath,\"r\"))!=NULL){//加载磁盘文件 fread(BaseAddr,sizeof(char),DiskSize,fp); printf(\"加载磁盘文件( %s )成功,现在可以进行操作了!\\n\\n\ } else{ printf(\"这是你第一次使用该文件管理系统!\正在初始化...\\n\"); format(); printf(\"初始化已经完成,现在可以进行操作了!\\n\\n\"); } while(1){ cout< 17 如文档对您有帮助,欢迎下载支持,谢谢! } changePath(command); } else if(cmd==\"create\"){ cin>>command; create(command); } else if(cmd==\"write\"){ cin>>command; write(command); } else if(cmd==\"read\"){ cin>>command; read(command); } else if(cmd==\"rm\"){ cin>>command; delfile(command); } else if(cmd==\"open\"){ cin>>command; open(command); } else if(cmd==\"close\"){ cin>>command; close(command); } else if(cmd==\"exit\"){ exit(); break; } else cout<<\"无效指令,请重新输入:\"< 18 因篇幅问题不能全部显示,请点此查看更多更全内容