操作系统课程设计报告
简单文件系统的实现
专业: 计算机科学与技术
班级:
姓名:
学号:
指导老师:
09056011
葛吉雄
09056020
胡志凌
2012.5.23
一、课程设计的目的
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+等组合,字符“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 主要函数功能实现:
format(); // 格式化磁盘
int
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);//读取文件
7 主要的框架
四、程序实现和程序调试遇到的问题的分析
1 对于 DOS 的文件操作使用不熟悉,经常输入错误命令
2 调试的时候跟踪变量的时候,难以锁定实际的变量是什么
3 对于文件的存储结构不熟悉,在构造 FAT 的时候不知如何解决,查阅了大量的资料和跟老师交流才慢慢开
始理解
4 由于买的实验册对于文件的介绍过于简单,导致理解上出现很大的困难。
五、结果分析和总结
1 基本上实现了 DOS 下简单文件系统的实现,通过学习基本掌握了文件系统的存储结构
2 当遇到困难的时候通过认真思考很查阅资料很大问题都是可以自己解决的。通过这次实验锻炼了自己的动
手的能力和分析问题的能力
3 在构造函数的时候可以开阔思维同时加深自己对文件系统实现的理解
4 通过这样的实验开始对 DOS 的环境文件命令输入有了初步的理解
5 通过跟老师的讨论解决自己心中的疑惑
六、程序清单如下:
#include
#include
#include
#include
using namespace std;
#define GENERAL 1//1 代表普通文件 2 代表目录文件 0 表示空文件
#define DIRECTORY 2
#define Zero 0
struct FCB
{
char fname[16]; //文件名
char type;
int size;
int fatherBlockNum;
int currentBlockNum;
// 0 空文件 1 目录文件 2 空文件
//文件大小
//当前的父目录盘块号
//当前的盘块
void initialize()
{
strcpy(fname,"\0");
type = Zero;
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
{
//用户文件打开表
//当前打开文件数
//FCB 拷贝
int files;
FCB f[OPEN_MAX];
OPENLIST()
{
files=0;
for(int i=0;i
FAT1[0]=FAT1[1]=FAT1[2]=-2; //0,1,2 盘块号依次代表 FAT1,FAT2,根目录区
FAT2[0]=FAT2[1]=FAT2[2]=-2;
root.init(2,2,"C:\\");//根目录区
memset(data,0,sizeof(data));//数据区
//FAT 作备份
}
};
//磁盘文件地址
//当前路径
//虚拟磁盘空间基地址
FILE *fp;
char * BaseAddr;
string currentPath="C:\\";
int current=2;
string cmd;
struct DISK *osPoint;
char command[16];
struct OPENLIST* openlist; //用户文件列表指针
//当前目录的盘块号
//输入指令
//磁盘操作系统指针
//文件名标识
format();
int
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;
/*-------保存到磁盘上 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;ifcb[i].type==DIRECTORY && strcmp(dir->fcb[i].fname,sonfname)==0 ){
printf("该文件夹下已经有同名的文件夹存在了!\n");
return 0;
}
}
for(i = 1;i < BlockFcbCount; i++){//查找空白 fcb 序号
if(dir->fcb[i].type==Zero)
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;
//填写该分派新的盘块的参数
strcpy(dir->fcb[temp].fname,sonfname);
//2 表示分配给下级目录文件