简单文件系统的实现实验报告.docx
《简单文件系统的实现实验报告.docx》由会员分享,可在线阅读,更多相关《简单文件系统的实现实验报告.docx(29页珍藏版)》请在冰豆网上搜索。
简单文件系统的实现实验报告
操作系统课程设计报告
简单文件系统的实现
专业:
班级:
姓名:
学号:
老师:
一、课程设计的目的
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(constchar*filename,constchar*mode)
(2)功能:
按照指定打开方式打开指定文件。
(3)输入参数说明:
filename:
待打开的文件名,如果不存在就创建该文件。
mode:
文件打开方式,常用的有:
"r":
为读而打开文本文件(不存在则出错)。
"w":
为写而打开文本文件(若不存在则创建该文件;反之,则从文件起始位置写,原内容将被覆盖)。
"a":
为在文件末尾添加数据而打开文本文件。
(若不存在则创建该文件;反之,在原文件末尾追加)。
"r+":
为读和写而打开文本文件。
(读时,从头开始;在写数据时,新数据只覆盖所占的空间,其后不变)。
"w+":
首先建立一个新文件,进行写操作,随后可以从头开始读。
(若文件存在,原内容将全部消失)。
"a+":
功能与"a"相同;只是在文件末尾添加新的数据后,可以从头开始读。
另外,上述模式字符串中都可以加一个“b”字符,如rb、wb、ab、rb+、wb+、ab+等组合,字符“b”表示fopen()函数打开的文件为二进制文件,而非纯文字文件。
(4)输出:
一个指向FILE类型的指针。
2.关闭文件函数fclose()
(1)格式:
intfclose(FILE*stream);
(2)功能:
用来关闭先前fopen()打开的一个文件。
此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。
(3)输入参数说明:
stream:
指向要关闭文件的指针,它是先前执行fopen()函数的返回值。
(4)输出:
若关闭文件成功则返回0;有错误发生时则返回EOF并把错误代码存到errno。
3.读文件函数fread()
(1)格式:
size_tfread(void*buffer,size_tsize,size_tcount,FILE*stream);
(2)功能:
读二进制文件到内存。
(3)输入参数说明:
buffer:
用于存放输入数据的缓冲区的首地址;
stream:
使用fopen()打开的文件的指针,用于指示要读取的文件;
size:
每个数据块的字节数;
count:
要读入的数据块的个数;
size*count:
表示要求读取的字节数。
(4)输出:
实际读取的数据块的个数。
4.写文件函数fwrite()
(1)格式:
size_tfwite(constvoid*buffer,size_tsize,size_tcount,FILE*stream);
(2)功能:
将数据写到二进制文件中。
(3)输入参数说明:
buffer:
用于存放输出数据的缓冲区的首地址;
stream:
使用fopen()打开的文件的指针,用于指示要写出的文件;
size:
每个数据块的字节数;
count:
要写出的数据块的个数;
size*count:
表示要求写出的字符数。
(4)输出:
实际写出的数据块的个数。
5.判断文件结束函数feof()
(1)格式:
intfeof(FILE*stream)
(2)功能:
用来判断是否已读取到文件末尾。
(3)输入参数说明:
stream:
使用fopen()打开的文件的指针,用于指示要判断的文件。
(4)输出:
如果已读到文件尾则返回非零值,其他情况返回0。
6主要函数功能实现:
intformat();//格式化磁盘
intmkdir(char*sonfname);//创建子目录
intrmdir(char*sonfname);//删除子目录
intcreate(char*name);//创建文件
intlistshow();//显示子文件信息
intdelfile(char*name);//删除文件
intchangePath(char*sonfname);//更改当前路径
intwrite(char*name);//写入文件
intexit();//退出系统
intopen(char*file);//打开文件
intclose(char*file);//关闭文件
intread(char*file);//读取文件
7主要的框架
四、程序实现和程序调试遇到的问题的分析
1对于DOS的文件操作使用不熟悉,经常输入错误命令
2调试的时候跟踪变量的时候,难以锁定实际的变量是什么
3对于文件的存储结构不熟悉,在构造FAT的时候不知如何解决,查阅了大量的资料和跟老师交流才慢慢开始理解
4由于买的实验册对于文件的介绍过于简单,导致理解上出现很大的困难。
五、结果分析和总结
1基本上实现了DOS下简单文件系统的实现,通过学习基本掌握了文件系统的存储结构
2当遇到困难的时候通过认真思考很查阅资料很大问题都是可以自己解决的。
通过这次实验锻炼了自己的动手的能力和分析问题的能力
3在构造函数的时候可以开阔思维同时加深自己对文件系统实现的理解
4通过这样的实验开始对DOS的环境文件命令输入有了初步的理解
5通过跟老师的讨论解决自己心中的疑惑
六、程序
#include
#include
#include
#include
usingnamespacestd;
#defineGENERAL1//1代表普通文件2代表目录文件0表示空文件
#defineDIRECTORY2
#defineZero0
structFCB
{
charfname[16];//文件名
chartype;//0空文件1目录文件2空文件
intsize;//文件大小
intfatherBlockNum;//当前的父目录盘块号
intcurrentBlockNum;//当前的盘块
voidinitialize()
{
strcpy(fname,"\0");
type=Zero;
size=0;
fatherBlockNum=currentBlockNum=0;
}
};
constchar*FilePath="C:
\\myfiles";/*常量设置*/
constintBlockSize=512;//盘块大小
constintOPEN_MAX=5;//能打开最多的文件数
constintBlockCount=128;//盘块数
constintDiskSize=BlockSize*BlockCount;//磁盘大小
constintBlockFcbCount=BlockSize/sizeof(FCB);//目录文件的最多FCB数
intOpenFileCount=0;//统计当前打开文件数目
structOPENLIST//用户文件打开表
{
intfiles;//当前打开文件数
FCBf[OPEN_MAX];//FCB拷贝
OPENLIST()
{
files=0;
for(inti=0;if[i].fatherBlockNum=-1;//为分配打开
f[i].type=GENERAL;
}
}
};
structdirFile/*-------------目录文件结构---------------*/
{
structFCBfcb[BlockFcbCount];
voidinit(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(inti=1;ifcb[i].fatherBlockNum=_CurrentBlockNum;//标记为子项
fcb[i].type=Zero;//标记为空白项
}
}
};
structDISK/**********************************************************************/
{
intFAT1[BlockCount];//FAT1
intFAT2[BlockCount];//FAT2
structdirFileroot;//根目录
chardata[BlockCount-3][BlockSize];
voidformat(){
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;//虚拟磁盘空间基地址
stringcurrentPath="C:
\\";//当前路径
intcurrent=2;//当前目录的盘块号
stringcmd;//输入指令
structDISK*osPoint;//磁盘操作系统指针
charcommand[16];//文件名标识
structOPENLIST*openlist;//用户文件列表指针
intformat();
intmkdir(char*sonfname);
intrmdir(char*sonfname);
intcreate(char*name);
intlistshow();
intdelfile(char*name);
intchangePath(char*sonfname);
intwrite(char*name);
intexit();
intopen(char*file);
intclose(char*file);
intread(char*file);
/*------------初始化-----------------------*/
intformat()
{
current=2;
currentPath="C:
\\";//当前路径
osPoint->format();//打开文件列表初始化
deleteopenlist;
openlist=newOPENLIST;
/*-------保存到磁盘上myfiles--------*/
fp=fopen(FilePath,"w+");
fwrite(BaseAddr,sizeof(char),DiskSize,fp);
fclose(fp);
printf("格式化成功!
!
\n");
return1;
}
intmkdir(char*sonfname)/*-----------------------创建子目录-------------------*/
{//判断是否有重名寻找空白子目录项寻找空白盘块号当前目录下增加该子目录项分配子目录盘块,并且初始化修改fat表
inti,temp,iFAT;
structdirFile*dir;//当前目录的指针
if(current==2)//根目录
dir=&(osPoint->root);
else
dir=(structdirFile*)(osPoint->data[current-3]);
/*--------为了避免该目录下同名文件夹--------*/
for(i=1;iif(dir->fcb[i].type==DIRECTORY&&strcmp(dir->fcb[i].fname,sonfname)==0){
printf("该文件夹下已经有同名的文件夹存在了!
\n");
return0;
}
}
for(i=1;iif(dir->fcb[i].type==Zero)
break;
}
if(i==BlockFcbCount){
printf("该目录已满!
请选择新的目录下创建!
\n");
return0;
}
temp=i;
for(i=3;iif(osPoint->FAT1[i]==0)
break;
}
if(i==BlockCount){
printf("磁盘已满!
\n");
return0;
}
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=(structdirFile*)(osPoint->data[iFAT-3]);//定位到子目录盘块号
dir->init(current,iFAT,sonfname);//iFAT是要分配的块号,这里的current用来指要分配的块的父块号
printf("创建子目录成功!
\n");
return1;
}
intrmdir(char*sonfname)/*-------删除当前目录下的文件夹--------*/
{
inti,temp,j;//确保当前目录下有该文件,并记录下该FCB下标
structdirFile*dir;//当前目录的指针
if(current==2)
dir=&(osPoint->root);
else
dir=(structdirFile*)(osPoint->data[current-3]);
for(i=1;iif(dir->fcb[i].type==DIRECTORY&&strcmp(dir->fcb[i].fname,sonfname)==0){
break;
}
}
temp=i;
if(i==BlockFcbCount){
printf("当前目录下不存在该子目录!
\n");
return0;
}
j=dir->fcb[temp].currentBlockNum;
structdirFile*sonDir;//当前子目录的指针
sonDir=(structdirFile*)(osPoint->data[j-3]);
for(i=1;iif(sonDir->fcb[i].type!
=Zero)
{
printf("该文件夹为非空文件夹,为确保安全,请清空后再删除!
\n");
return0;
}
}
/*开始删除子目录操作*/
osPoint->FAT1[j]=osPoint->FAT2[j]=0;//fat清空
char*p=osPoint->data[j-3];//格式化子目录
memset(p,0,BlockSize);
dir->fcb[temp].initialize();//回收子目录占据目录项
printf("删除当前目录下的文件夹成功\n");
return1;
}
/*-----------在当前目录下创建文本文件---------------*/
intcreate(char*name){
inti,iFAT;//temp,
intemptyNum=0,isFound=0;//空闲目录项个数
structdirFile*dir;//当前目录的指针
if(current==2)
dir=&(osPoint->root);
else
dir=(structdirFile*)(osPoint->data[current-3]);
for(i=1;i{
if(dir->fcb[i].type==Zero&&isFound==0){
emptyNum=i;
isFound=1;
}
elseif(dir->fcb[i].type==GENERAL&&strcmp(dir->fcb[i].fname,name)==0){
printf("无法在同一目录下创建同名文件!
\n");
return0;
}
}
if(emptyNum==0){
printf("已经达到目录项容纳上限,无法创建新目录!
\n");
return0;
}
for(i=3;i{
if(osPoint->FAT1[i]==0)
break;
}
if(i==BlockCount){
printf("磁盘已满!
\n");
return0;
}
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");
return1;
}
/*-------查询子目录------------*/
intlistshow()
{
inti,DirCount=0,FileCount=0;
//搜索当前目录
structdirFile*dir;//当前目录的指针
if(current==2)
dir=&(osPoint->root);
else
dir=(structdirFile*)(osPoint->data[current-3]);
for(i=1;iif(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);
return1;
}
/*---------在当前目录下删除文件-----------*/
intdelfile(char*name)
{
inti,temp,j;
//确保当前目录下有该文件,并且记录下它的FCB下标
structdirFile*dir;//当前目录的指针
if(current==2)