资源描述
操作系统专业课程设计文件系统目录管理
文 件 管 理 系 统
——目录文件管理的设计
目 录
第一章 课程设计目的和要求 1
1 课程设计目的 1
2 课程设计要求 1
课程设计思想原理 1
课程题目 1
提交课程设计报告 2
第二章 课程设计内容 3
1 文件管理系统结构 3
2 文件系统采用索引文件结构 3
磁盘模拟 3
3
3
5
第三章 详细设计 7
1 程序功能模块图 7
2 实体关系图 7
3 数据流图 8
4 数据结构设计 8
5 程序流程图 11
建立文件目录(mkdir)程序流程图 11
删除文件目录(rmdir)程序流程图 12
第四章 程序运行与测试 13
1 程序运行主界面 13
2 用mkdir [dirname] 命令创建子目录 13
3用ls命令显示当前目录下信息 13
4 用rmdir [dirname] 命令删除子目录 14
5 用cd [dirname] 命令改名当前目录 14
第五章 课程设计总结 16
附录Ⅰ 参考文献 17
附录Ⅱ 程序清单 18
第一章 课程设计目的和要求
1 课程设计目的
操作系统课程主要讲述的内容是多道操作系统的原理与技术,与其它计算机原理、编译原理、汇编语言、计算机网络、程序设计等专业课程关系十分密切。本课程设计的目的综合应用学生所学知识,建立系统和完整的计算机系统概念,理解和巩固操作系统基本理论、原理和方法,掌握操作系统开发的基本技能。
通过模拟文件系统的实现,深入理解操作系统中文件系统的理论知识, 加深对教材中的重要算法的理解。同时通过编程实现这些算法,更好地掌握操作系统的原理及实现方法,提高综合运用各专业课知识的能力。
2 课程设计要求
课程设计思想原理
阅读操作系统方面的书籍,了解操作系统的文件系统原理。结合分析课程设计要求,确定实体以及它们之间的关系。实体关系有三张表(磁盘空间分配表、文件表、打开文件表)、一个模拟磁盘的空间、命令服务和用户构成。用户负责输入命令。命令服务实现命令的解释、命令检查以及调用相关模块执行相应的命令功能。
磁盘空间分配表,采用链表结构,每个节点保存模拟磁盘的一个逻辑块的信息,包括块的最大长度,文件占用长度,占用标志。如果占用标志为0,即该空间可分配给文件。初始化磁盘空间分配表链表,首先把整个模拟磁盘作来一块,,从头开始遍历,检查占用位,如果该块为可分配,则检查块大小,若块长度大于或等于申请空间大小,则把块的前一部分(等于申请大小)分配给文件,并置标志位为占用。剩下的大小作来一个新块,作来一个新节点插入到原节点的后边,标志位为可用。这样就实现了模拟磁盘的线性分配。
构造这些实体的关系图,数据流图、程序流程图来进行具体的设计。
课程题目
要求设计一个文件系统目录模拟程序,通过该程序能够实现简单的目录管理操作:
● 创建多级目录 设计树型目录结构,能够从根目录开始创建树状的多级子目录。
● 删除子目录 实现删除当前目录下的子目录操作。
● 显示当前目录下信息 能够实现显示当前目录下子目录及文件信息的操作。
● 更改当前目录 通过操作可以改变当前目录,返回上级目录或进入下级子目录。
● 在目录下创建文件 能够在目录下实现创建文件的操作。
提交课程设计报告
在规定的时间完成课程设计各阶段的任务,最后提交详细的课程设计报告。
第二章 课程设计内容
1文件管理系统结构
●文件的逻辑结构
●文件的物理结构
●目录结构
●磁盘分配回收
●文件的保护
●用户接口
2文件系统采用索引文件结构
磁盘模拟
磁盘是断电后内容不丢失的,因此用文件模拟磁盘。要求模拟系统存在两块硬盘:
●用一个文件FAT1模拟磁盘c
●磁盘的每个盘块512字节,模拟磁盘共有128块。
●磁盘中第0块存放专用块内容,第1、2块存放根目录,其余存放子目录和文件。
文件的逻辑结构采用流式结构;
文件的内容均采用文本文件,系统中有两种文件:
一种是存放任意字符的文件
一种是可执行文件:可执行文件的内容就是系统内进程的程序体。
目录结构采用树型目录结构。
(16个字节):
●目录名、文件名:6个字节;
●扩展名:3个字节(可执行文件扩展名为exe,目录没有扩展名);
●目录、文件属性:1字节;
●文件长度:2字节(目录没有长度,字节数)。
●地址:直接地址项1个,一级索引项1个;
●预留1字节
根目录位置固定,占用磁盘2块,大小固定,共16项,占用模拟磁盘第1、2块;
位置不固定,大小不固定(至少建立一级子目录,最好支持多级子目录)。
●磁盘的分配采用混合索引结构的分配方式。系统采用成组链接法记录磁盘空间的使用情况。
●空闲块每组登记10个空闲块,专用块占用第0块。
●索引块中每个盘块号占用4字节,登记32块
图2-1 文件系统目录映射方式
图2-2 文件块的分配
用户接口提供用户接口操作命令,要求实现以下命令:
(1) 创建目录:mkdir [dirname]
在当前目录下建立子目录,若有同名文件夹存在或目录已满,则程序进行提示,并拒绝创建。
(2) 删除目录:rmdir [dirname]
在删除目录前,系统要求用户进行确认删除
(3) 显示当前目录下信息:ls
输入ls命令后,系统会显示当前目录下所有子目录和文件的信息,包括文件名,文件类型等信息
(4) 改变当前目录:cd [dirname]
通过该命令可改变当前目录,进入上级目录或下级子目录
(5) 创建文件:create [filename]
在目录下创建一个文本文件文件
屏幕显示
屏幕显示要求包括:
(1)用户命令接口,用于系统运行时用户输入命令;
(2)磁盘目录显示,要求显示磁盘的树型目录结构;
(3)磁盘使用情况,显示磁盘每一个磁盘块的空间是否空闲。
第三章 详细设计
1 程序功能模块图
文件系统提供的目录操作有建立目录(mkdir)、删除目录(rmdir)、显示目录下内容(ls)、改变当前目录(cd)、创建文件(create)。可以通过键盘输入命令来模拟文件的操作。通过exit命令退出程序。
图3-1 模拟文件系统模块图
2 实体关系图
命令服务使得用户能够输入命令,在需要时提供命令的帮助。同时能够分析命令,调用相应的命令模块对模拟磁盘、磁盘空间分配表、文件表、打开文件表进行操作。磁盘空间分配表记录模拟磁盘的使用情况。文件表记录文件的信息和在磁盘里的位置等信息。打开文件表记录已打开的文件,对应文件表中的文件信息,和文件表里的文件节点类似,记录了文件在模拟磁盘中的信息。
3 数据流图
4 数据结构设计
通过分析课程设计要求,具体设计出如下数据结构:
(1) 定义常量
const char* FilePath = "C:\\myfiles";
const int BlockSize = 512; //盘块大小
const int BlockCount = 128; //盘块数
const int DiskSize = BlockSize*BlockCount; //磁盘大小
const int BlockFcbCount= BlockSize/sizeof(FCB);//目录文件的最多FCB数
通过定义常量确定模拟文件系统磁盘的路径,以及文件块的大小,盘块数,以及分配的磁盘大小和目录文件的最多文件控制块(FCB)数目。
(2) 文件控制块结构体定义
struct FCB //文件控制块
{
char fname[16]; //文件名
char type; //文件类型
int size; //文件大小
int fatherBlockNum; //父目录块号
int currentBlockNum; //当前的盘块
void chushihua()
{
strcpy(fname,"\0");
type = NULL;
size =0;
fatherBlockNum = currentBlockNum = 0;
}
};
通过结构体类型定义了文件控制块 ,文件控制块包括文件名,文件类型,文件大小,父目录块号,以及当前盘块,并且对文件控制块进行了初始化操作。文件控制块用来对文件进行管理。
(3) 目录文件结构
struct dirFile
{
struct FCB fcb[BlockFcbCount];
void init(int _FatherBlockNum,int _CurrentBlockNum,char *name)//父块号,当前块号,目录名
{
strcpy(fcb[0].fname,name); //本身的FCB
fcb[0].fatherBlockNum=_FatherBlockNum;
fcb[0].currentBlockNum=_CurrentBlockNum;
fcb[0].type=DIRECTORY; //标记目录文件
for(int i=1;i<BlockFcbCount;i++){
fcb[i].fatherBlockNum=_CurrentBlockNum; //标记为子项
fcb[i].type=NULL; // 标记为空白项
}
}
};
该结构体定义了目录文件结构,目录文件采用FCB结构体数组方式进行组织管理,用来存储新创建的目录,把目录的相关信息保存在文件控制块结构体中。
(4)磁盘结构体定义
struct DISK
{
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作备份
(2,2,"C:\\");//根目录区
memset(data,0,sizeof(data));//数据区
}
};
用文件模拟磁盘。要求模拟系统存在两块硬盘:
●用一个文件FAT1模拟磁盘c
●磁盘的每个盘块512字节,模拟磁盘共有128块。
●磁盘中第0块存放专用块内容,第1、2块存放根目录,其余存放子目录和文件。
5 程序流程图
建立文件目录(mkdir)程序流程图
图3-4 mkdir程序流程图
删除文件目录(rmdir)程序流程图
开始
查询打开文件表
在打开文件表里?
不在
查询文件表
在文件表里?
在
删除该文件节点
定位该文件在磁盘分配表中的节点,置标志为空闲
删除打开文件表中该文件条目
显示删除成功
返回
显示无此文件
返回
显示无法删除
返回
在
图3-5 rmdir程序流程图
第四章 程序运行与测试
1 程序运行主界面
图4-1 程序主界面
2 用mkdir [dirname] 命令创建子目录
图4-2 mkdir命令运行结果
3用ls命令显示当前目录下信息
图4-3 ls命令运行结果
4 用rmdir [dirname] 命令删除子目录
通过执行该命令可以看到,若删除的子目录不存在,系统将给出提示。
图4-4 rmdir命令运行结果
5 用cd [dirname] 命令改名当前目录
通过该图可看到当前目录已从 C:\ 变为 C:\project\ ,命令执行成功
图4-5 cd命令运行结果
图4-6 在子目录下创建文件
第五章 课程设计总结
通过本次的课程设计,使我能够正确运用操作系统课程中所学的基本理论和知识,加深了对文件系统基本概念的理解,以及磁盘文件系统的文件操作。还有让我感受挺深的是对软件工程方法的应用。设计一个软件,先要做好需求分析,这一点很重要,如果没有分析好需求,到软件设计的最后,发现所做的功能不符合要求,那么一切都得重做,前面所有的努力都付诸东流。还有比较重要的是,写好E-R图,至少画出语境级的数据流图,以及仔细画好程流程图。在程序设计的开始,由于分析工作做得不够深入和细致,吃了点小苦头。对于这样一个小设计来说,都会吃苦头,要是大工程更是无法想像,有可能会项目失败。以后得加强对软件工程的学习。另外在运用C语言的时候,感觉有点生疏,在组织语言时时而出错,在编程和调试的过程中,经常会出现意想不到的问题,并非每个问题都可以从相关资料中找到解决方法,有些问题是无法预料到的,这就需要通过自己理性的分析得出问题的解决方案。
在设计过程中,查询了不少相关资料,不断的发现问题、提出问题、解决问题。在对自己所编写的源程序段的纠错的过程中,使我更好的理解了操作系统中文件系统的理论知识,同时在编程时用到了模块化的设计思想,这种编程方法可以使我们的编程变的更简单,可以使我们的查错与纠错变的更方便。总的来说通过这次的设计的学习使我学到了很多在平时的学习中学不到的很多东西,通过这次课程设计,使我对操作系统和编程产生兴趣,我想我会在这条路上继续前进下去。我相信,只要不断的严格要求自己,注意培养自己的思维能力,就一定会有更大更辉煌的发展和提高。
附录Ⅰ 参考文献
[1] 张尧学等编著. :清华大学出版社,
[2] :西安电子科技出版社,
[3] 陈向群 :北京大学出版社,
[4] 罗宇 :机械工业出版社,
附录Ⅱ 程序清单
#include <>
#include <>
#include <string>
#include <iostream>
using namespace std;
#define GENERAL 1 //普通文件
#define DIRECTORY 2 //目录文件
#define NULL 0 //空文件
struct FCB //文件控制块
{
char fname[16]; //文件名
char type; //文件类型
int size; //文件大小
int fatherBlockNum; //父目录块号
int currentBlockNum; //当前的盘块
void chushihua()
{
strcpy(fname,"\0");
type = NULL;
size =0;
fatherBlockNum = currentBlockNum = 0;
}
};
//定义常量
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<OPEN_MAX;i++){
f[i].fatherBlockNum=-1;//为分配打开
f[i].type=GENERAL;
}
}
};
//目录文件结构
struct dirFile
{
struct FCB fcb[BlockFcbCount];
void init(int _FatherBlockNum,int _CurrentBlockNum,char *name)//父块号,当前块号,目录名
{
strcpy(fcb[0].fname,name); //本身的FCB
fcb[0].fatherBlockNum=_FatherBlockNum;
fcb[0].currentBlockNum=_CurrentBlockNum;
fcb[0].type=DIRECTORY; //标记目录文件
for(int i=1;i<BlockFcbCount;i++){
fcb[i].fatherBlockNum=_CurrentBlockNum; //标记为子项
fcb[i].type=NULL; // 标记为空白项
}
}
};
struct DISK
{
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作备份
(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 changePath(char *sonfname);
int exit();
//系统初始化
int format()
{
current = 2;
currentPath="C:\\"; //当前路径
osPoint->format();//打开文件列表初始化
delete openlist;
openlist=new OPENLIST;
/*-------保存到磁盘上myfiles--------*/
fp = fopen(FilePath,"w+");
fwrite(BaseAddr,sizeof(char),DiskSize,fp);
fclose(fp);
printf("----------------------------------------------------------\n\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<BlockFcbCount;i++)
{
if(dir->fcb[i].type==DIRECTORY && strcmp(dir->fcb[i].fname,sonfname)==0 )
{
printf("该文件夹下已经有同名的文件夹存在了!\n");
return 0;
}
}
//查找空白fcb序号
for(i=1;i<BlockFcbCount;i++)
{
if(dir->fcb[i].type==NULL)
break;
}
if(i==BlockFcbCount)
{
printf("该目录已满!请选择新的目录下创建!\n");
return 0;
}
temp=i;
for(i = 3;i < BlockCount;i++)
{
if(osPoint->FAT1[i] == 0)
break;
}
if(i == BlockCount)
{
printf("磁盘已满!\n");
return 0;
}
iFAT=i;
//接下来进行分配
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\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<BlockFcbCount;i++)
{ //查找该目录文件
if(dir->fcb[i].type==DIRECTORY && strcmp(dir->fcb[i].fname,sonfname)==0)
{
break;
}
}
temp=i;
if(i==BlockFcbCount)
{
printf("当前目录下不存在该子目录!\n");
return 0;
}
j = dir->fcb[temp].currentBlockNum;
struct dirFile *sonDir; //当前子目录的指针
sonDir=(struct dirFile *)(osPoint->data [ j - 3]);
for(i=1;i<BlockFcbCount;i++) //查找子目录是否为空目录
{
if(sonDir->fcb[i].type!=NULL)
{
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].chushihua(); //回收子目录占据目录项
printf("---------------------------------------------------------------\n\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<BlockFcbCount;i++)
{
if(dir->fcb[i].type==GENERAL)
{ //查找普通文件
FileCount++;
printf("%s 文本文件.\n",dir->fcb[i].fname);
}
if(dir->fcb[i].type==DIRECTORY)
{ //查找目录文件
DirCount++;
printf("%s 文件夹.\n",dir->fcb[i].fname);
}
}
printf("\n该目录下共有 %d 个文本文件, %d 个文件夹\n\n",FileCount,DirCount);
printf("--------------------------------------------------------\n\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 = (0,() - strlen(dir->fcb[0].fname )-1);
return 1;
}
/*进入子目录*/
int i,temp;
//确保当前目录下有该目录,并且记录下它的FCB下标
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;
}
//修改当前文件信息
current=dir->fcb [temp].currentBlockNum ;
currentPath = currentPath+dir->fcb [temp].fname +"\\";
printf("-------------------------------------------------------------\n\n");
return 1;
}
//退出系统
int exit()
{
//将所有文件都关闭
//保存到磁盘上C:\myfiles
fp=fopen(FilePath,"w+");
fwrite(BaseAddr,sizeof(char),DiskSize,fp);
fclos
展开阅读全文