昆明理工大学信息工程与自动化学院学生实验报告
( 201 —201 学年 第 二 学期 )
课程名称:操作系统 开课实验室: 年 月 日
一、实验目的
用C或C++语言编写和调试一个简单的文件系统,模拟文件管理的基本功能。从而对各种文件操作命令的实质内容和执行过程有比较深入的了解。
二、实验原理及基本技术路线图(方框原理图)
用C模拟实现文件系统的管理;要求设计一个多级目录结构的文件系统,能正确描述文件控制块,采用合理的外存分配方式,能实现基本的目录及文件的操作,包括创建、删除、重命名、复制、移动等功能,并对文件有一定的存取权限控制。
功能设计 :
Help dir exit create [文件名] cdir [目录名] read [文件名] close[文件名] edit [文件名] cd [目录名] attr [文件名] del [文件名] rename [文件名] 显示命令帮助 显示当前目录下的文件和文件夹 退出系统 创建文本文件 创建文件夹 读取一个文件最多可同时读取五个 关闭一个文件 编辑一个文件 进子目录或者上级目录 显示该文件的属性 删除文件 重命名
编辑功能流程图
删除文件流程图 创建文件流程图
核心算法:
bool Format(void); //格式化 bool install(void); //装载虚拟硬盘的数据 void login(void); /用户登陆
void showMenu(void);//显示功能菜单 bool onAction(void);//用户选择功能并执行 void createFile(string str);//创建文件 bool read(string str);//读取文件 void editFile(string str);//编辑文件 void Delete(string str);//删除一个文件
数据结构:
始地址
/*inode结构体*/ struct inode{ unsigned short di_tag; /*inode标识*/
/*关联文件数,当为0时表示删除文件,如一个目录至少
包含两个文件:"."和".."*/ const unsigned int ACCOUNT_NUM=10; //用户数量 /*---------常变量------*/ const unsigned int BLOCK_SIZE=512; //块长 const unsigned int DATA_BLOCK_NUM=512; //数据块数量 const unsigned int DINODE_START=4*BLOCK_SIZE; //inode起始位置 const unsigned int DINODE_SIZE=512; const unsigned int DINODE_NUM=32; //inode大小 //inode数量 const unsigned int DATASTART=(2+DINODE_NUM)*BLOCK_SIZE; //数据区的开 unsigned short di_number;
unsigned short di_mode; /*存取模式:0为目录,1为文件*/
unsigned short di_userID; /*当前inode所属用户 0为根目录ID,一次下去是管理员目
录、用户目录*/ unsigned short di_access; /*访问权限 0为不允许普通用户访问(公共目录),1为允许 普通用户访问*/
};
unsigned short di_size; /*文件大小,目录没有大小,值为0*/ unsigned short di_ctime; /* 创建时间 */ unsigned short di_mtime; /* 最后一次修改时间*/ unsigned short di_block[DATA_BLOCK_NUM]; /* 数据块块地址编号 */
/**超级块***/
struct super_block{
};
/**账户信息**/
struct user{
};
/**文件/目录结构**/
struct directory{
unsigned short s_inodes_count; /* 文件系统中inode的总数 */ unsigned short s_blocks_count; /* 数据块总数 */ unsigned short s_r_blocks_count; /* 保留块总数 */ unsigned short s_free_blocks_count; // 空闲块总数 unsigned short s_free_inodes_count; /* 空闲的inode总数 */ unsigned short s_log_block_size; /* block 的大小 */ unsigned short user_id; //用户ID unsigned short user_access; //权限 string username; string password; //用户名 //密码
};
string name; /*目录名*/ unsigned short d_ino; /*目录号*/
三、所用仪器、材料(设备名称、型号、规格等)。
计算机一台
四、实验方法、步骤
#include
#include
#include
#include
struct OpenFileTable
{
long offset;
char file_name[10];
long int file_start;
long int file_length;
};
struct FCB_Block
{
int flag; //打开文件表数据结构 // 当前文件读写指针 // 文件名数组 // 文件起始块号 // 文件长度(字节) //FCB数据结构 // 标志,-1表示未用,1表示文件用
char file_name[10]; // 文件名数组 long int file_date; // 文件建立日期
long int file_time; // 文件建立时间
};
struct Super_Block // 超级块数据结构, 文件系统的分区信息,存放在0#物理块中
{
unsigned long int fs_totalsize; // 整个分区的总磁盘物理块数 unsigned long int fs_freesize; // 分区的所有空闲磁盘物理块数 unsigned int fs_blocksize; // 文件系统的物理块大小(字节) unsigned int fs_fat_start; // FAT的起始磁盘物理块号 unsigned int fs_fat_size; // FAT占用的磁盘物理块数 unsigned int fs_dir_start; // 根目录的起始磁盘物理块号 unsigned int fs_dir_size; // 根目录占用的磁盘物理块数 unsigned int fs_data_start; // 数据区起始磁盘物理块号 unsigned long int fs_data_size; // 数据区的磁盘物理块数 long int file_start; // 文件起始块号 long int file_length; // 文件长度(字节)
};
const char DiskName[]="FileSys.dat"; //磁盘文件名
char rw_buffer[512]; // 读写使用的缓冲区
struct FCB_Block filefcb[130]; // 读写目录使用的数据结构
struct Super_Block FsSupBlk; // 读写超级块使用的数据结构
long int fat_buffer[5000]; // 读写FAT使用的缓冲区,为简化在系统启动时全部装入内存,0为空闲
struct OpenFileTable OFT[16]; // 打开文件表,当前只使用OFT[0]
unsigned int block_size; // 物理块大小(字节)
unsigned long int total_disk_size; // 磁盘总容量(物理块数)
unsigned int total_dir_size; // 目录占有的物理块数
unsigned int total_fat_size; // FAT占有的物理块数
long int find_fcb; // 记录读FCB块的次数
FILE *fsPtr; // 模拟磁盘的文件指针
/*********************** 磁盘块的申请***********************************/
unsigned long int Get_Block(unsigned long int count) //分配count个物理快,返回首块指针,其它已经连接
{
unsigned long int tmp,firstblk,tmpcount; unsigned long int i;
int flag=1;
if (count > FsSupBlk.fs_freesize)
{ printf(" ==== 没有足够磁盘容量,不能分配!==== \n"); return 0; }
tmpcount=0;
for(i=FsSupBlk.fs_data_start;i
}
/*********************** 磁盘块的回收***********************************/
void Put_Block(unsigned long int addr)
{ unsigned long int i,j;
{ if(fat_buffer[i] == 0) //文件未占有,分配 { if (flag==1) { firstblk=i; flag=-1;} else { fat_buffer[tmp]=i; } } tmp=i; fat_buffer[i]=-1; tmpcount++; } if(tmpcount==count) //分配完成 { FsSupBlk.fs_freesize=FsSupBlk.fs_freesize-count;//减少可分配物理块 return firstblk; } return -1; //分配不成功
int count;
i=addr; count=0;
while(fat_buffer[i]!=-1)
{ j=fat_buffer[i]; //下一项
fat_buffer[i] = 0;
fat_buffer[i] = 0;
FsSupBlk.fs_freesize=FsSupBlk.fs_freesize+count+1;//增加可分配物理块
return;
}
/*********************** 读磁盘块***********************************/
void Read_Block(unsigned long int addr,char *buf)
{
fseek(fsPtr,FsSupBlk.fs_blocksize*addr,SEEK_SET); if (addr>FsSupBlk.fs_totalsize) { printf(" ==== 超出磁盘容量,不能读!==== \n"); return; } count++; i=j; }
fread(buf,512,1,fsPtr);
}
return;
/*********************** 写磁盘块***********************************/
void Write_Block(unsigned long int addr,char *buf)
{
fseek(fsPtr,FsSupBlk.fs_blocksize*addr,SEEK_SET); if (addr>FsSupBlk.fs_totalsize) { printf(" ==== 超出磁盘容量,不能写!==== \n"); return; }
fwrite(buf,512,1,fsPtr);
}
/*********************** 格式化磁盘***********************************/
void Real_Format()
{
unsigned long int bcount; return;
long int fatval,i;
//更改系统超级块信息 char *c;
FsSupBlk.fs_totalsize=total_disk_size;
FsSupBlk.fs_blocksize=block_size;
FsSupBlk.fs_dir_start=1;
FsSupBlk.fs_dir_size=total_dir_size;
FsSupBlk.fs_fat_start=total_dir_size+1;
-11-
FsSupBlk.fs_fat_size=total_fat_size;
FsSupBlk.fs_data_start=FsSupBlk.fs_fat_start+FsSupBlk.fs_fat_size;
FsSupBlk.fs_data_size
FsSupBlk.fs_fat_size-1;
FsSupBlk.fs_freesize= FsSupBlk.fs_data_size;
//初始化FAT //初始化目录 for(i=0;i
fatval=FsSupBlk.fs_fat_start*512;
fseek(fsPtr,fatval,SEEK_SET); //定位文件指针
bcount=FsSupBlk.fs_fat_size+FsSupBlk.fs_dir_size+1; for(i=0;i
-12- for(;i
} //初始化数据区 for(i=0;i
/***********************新建系统磁盘文件
***********************************/
void Create_Disk()
{
// 建立磁盘文件
total=total_disk_size;
for(i=0;i
-13- long int i; unsigned long int total; fsPtr=fopen(DiskName,"wb+"); if(fsPtr==NULL) { } printf(" 不能建立磁盘所需的文件 !\n"); exit(0);
fwrite(rw_buffer,512,1,fsPtr);
fclose(fsPtr);
fsPtr=fopen(DiskName,"rb+");
Real_Format();
return;
}
/***********************读写系统超级块信息
***********************************/
void Read_Boot() //读取磁盘超级块数据信息
{
rewind(fsPtr);
}
void FileBoot() //超级块数据信息存盘
{
rewind(fsPtr);
fread(&FsSupBlk,sizeof(struct Super_Block),1,fsPtr); return; fwrite(&FsSupBlk,sizeof(struct Super_Block),1,fsPtr); return; -14-
}
/***********************FAT操作***********************************/
void LoadFat() //装载全部FAT到内存
{
fseek(fsPtr,FsSupBlk.fs_fat_start*512,SEEK_SET);
}
void SaveFat() //FAT到文件FAT区
{
}
/***********************显示超级块信息***********************************/ void boot_dis()
{
printf("FsSupBlk.fs_totalsize=%ld\n",FsSupBlk.fs_totalsize);
printf("FsSupBlk.fs_blocksize=%d\n",FsSupBlk.fs_blocksize);
printf("FsSupBlk.fs_dir_start=%d\n",FsSupBlk.fs_dir_start);
printf("FsSupBlk.fs_dir_size=%d\n",FsSupBlk.fs_dir_size);
-15- fread(fat_buffer,sizeof(long int),FsSupBlk.fs_totalsize ,fsPtr); return; fseek(fsPtr,FsSupBlk.fs_fat_start*512,SEEK_SET); fwrite(fat_buffer,sizeof(long int),FsSupBlk.fs_totalsize,fsPtr); return;
printf("FsSupBlk.fs_fat_start=%d\n",FsSupBlk.fs_fat_start);
printf("FsSupBlk.fs_fat_size=%d\n",FsSupBlk.fs_fat_size);
printf("FsSupBlk.fs_data_start=%d\n",FsSupBlk.fs_data_start);
printf("FsSupBlk.fs_data_size=%ld\n",FsSupBlk.fs_data_size);
printf("FsSupBlk.fs_freesize=%ld\n",FsSupBlk.fs_freesize);
}
/***********************系统初始化***********************************/
void Sys_Init() //初始化
{
Read_Boot();
//boot_dis(); fsPtr=fopen(DiskName,"rb+"); if(fsPtr == NULL) Create_Disk();
LoadFat();
}
/***********************显示操作***********************************/
void dir() //显示目录下的文件
{
int i,countFile=0; return;
char str[16];
long int n,pos_dir,pos_fat;
-16-
pos_dir=FsSupBlk.fs_dir_start*512;
pos_fat=FsSupBlk.fs_fat_start*512;
fseek(fsPtr,pos_dir,SEEK_SET); while(ftell(fsPtr)
for(i=0;i
if(filefcb[i].flag == 1) //文件占有
{ countFile++;
n = filefcb[i].file_length;
printf(" %-15s%15d bytes\n", filefcb[i].file_name,"file",n);
}
/*************************查找文件*******************************/
//查找文件,文件存在返回当前FCB数组下标,否则返回-1
-17- } } cout
int Find_File(char *filename)
{
int i; long int pos_dir,pos_fat;
pos_dir=FsSupBlk.fs_dir_start*512;
pos_fat=FsSupBlk.fs_fat_start*512;
find_fcb=0;
fseek(fsPtr,pos_dir,SEEK_SET); while(ftell(fsPtr)
for(i=0;i
if(filefcb[i].flag!=-1)
{ if(strcmp(filename,filefcb[i].file_name) == 0) return i;} //文件存在
return -1;
}
/*************************创建文件*******************************/
void create(char *fname,long int num) //在当前目录下创建一个名字为str的文件,长度为num
{
int i,j; //true表示没有与该名字重名的文件
int tempnode;
-18- }
long int pos_dir,getnum=0; unsigned long int blkcount; blkcount= num/512+1; //计算需要的物理块
if(FsSupBlk.fs_freesize
// 建立文件的处理 if (tempnode!=-1) //表示文件存在 { printf("\n 文件已经存在,不需要建立 !\n\n"); return;} tempnode=Find_File(fname); { } printf("\n 磁盘没有足够空间,不能建立 !\n\n"); return;
pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize;
fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区 for(i=0; i
if(filefcb[j].flag == -1) //找到空目录项 {
}
} // 分配空间, 标记FCB数据项,并将FCB写磁盘 getnum=Get_Block(blkcount); if(getnum==-1){ printf("不能分配存储空间 \n");return;} filefcb[j].file_start=getnum; filefcb[j].flag = 1; filefcb[j].file_length=num; strcpy(filefcb[j].file_name,fname); //filefcb[].file_time= //filefcb[].file_date= // 改变磁盘FCB值 pos_dir=pos_dir+sizeof(struct FCB_Block)*(i*16+j); fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区的FCB项fwrite(&filefcb[j],sizeof(struct FCB_Block),1 ,fsPtr); //Write_Block(i+FsSupBlk.fs_dir_start,(char *)filefcb); printf(" 文件占用了 %d 个物理块\n",blkcount); printf(" 系统还有 %ld 个物理块可用\n\n",FsSupBlk.fs_freesize); return;
-20-
//没有FCB项,不能建立文件
cout
return;
}
/*************************格式化*******************************/
void format()
{
char ch;
cout
cin>>ch;
if(ch=='y'||ch=='Y')
}
/****************************删除文件操作
**************************************/
void del(char *fname)
{
{ Real_Format(); printf("\n Format Successful!\n\n"); } long int tempnode; long int pos_dir; -21-
// 删除文件的处理 tempnode=Find_File(fname); if (tempnode==-1) //表示文件不存在 { printf("\n 文件不存在,不能删除 !\n\n"); return;}
Put_Block(filefcb[tempnode].file_start); // 释放文件存储空间
filefcb[tempnode].flag =-1; // 标记FCB项可用
// 修改的FCB项写回磁盘 pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize+((find_fcb-1)*16+tempnode)*sizeof(struct FCB_Block);
}
/*************************写文件*******************************/
void write(char *fname ,int num)//写文件,仅实现在文件尾部填加内容,并限制在512个字节内
{
int tempnode;
int i,j,x;
-22- fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区 fwrite(&filefcb[tempnode],sizeof(struct FCB_Block),1 ,fsPtr); return;
long int pos_dir;
rescount=filefcb[tempnode].file_length % FsSupBlk.fs_blocksize; char *string=new char [num]; //申请空间 for(i=0;i 512) { } tempnode=Find_File(fname); if (tempnode==-1) //表示文件不存在 { } // 写文件的处理 printf("\n 文件不存在,不能写 !\n\n"); return; printf("\n 不能写大于512字节的数据 !\n\n"); return; cin>>string[i]; }
if (num> FsSupBlk.fs_blocksize-rescount)
{ if (FsSupBlk.fs_freesize
} } printf("\n 文件系统没有足够空间,不能写 !\n\n"); return; for(j=filefcb[tempnode].file_start;fat_buffer[j]!=-1;j=fat_buffer[j]); Read_Block(j,rw_buffer);
if (num
{ } else { for(i=0;i
for(i=0;i
rw_buffer[rescount+i]=string[i]; Write_Block(j,rw_buffer);
fat_buffer[j]=Get_Block(1);
j=fat_buffer[j];
for(x=0;x
for(x=0;x
rw_buffer[x]=string[i+x]; Write_Block(j,rw_buffer); }
//delete []string;
-24-
// 修改FCB项并写回磁盘
filefcb[tempnode].file_length+=num; // 增加文件的长度
pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize+((find_fcb-1)*16+tempnode)*sizeof(struct FCB_Block);
fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区 fwrite(&filefcb[tempnode],sizeof(struct FCB_Block),1 ,fsPtr);
cin.ignore(10000,'\n'); //清除输入流缓冲区
}
void copyFcbtoOft(int fcbpos)
{
OFT[0].offset =0; strcpy(OFT[0].file_name,filefcb[fcbpos].file_name); cout
OFT[0].file_start = filefcb[fcbpos].file_start ;
OFT[0].file_length= filefcb[fcbpos].file_length ;
}
/*************************读文件*******************************/
void read(char *fname,long start,int count)//读文件 ,限制在512个字节内
{
int tempnode;
int stblknum,offset; -25- int dspnum;
tempnode=Find_File(fname); if (tempnode==-1) //表示文件不存在 { printf("\n 文件不存在,不能读 !\n\n"); return; } if (start > filefcb[tempnode].file_length) //读的数据超出文件范围 { printf("\n 超出文件范围,不能读 !\n\n"); return; } // 读文件的处理
printf("\n========================================\n");
stblknum=start/FsSupBlk.fs_blocksize+1; // 起始物理块
offset=start%FsSupBlk.fs_blocksize; // 起始物理块的偏移量
for(i=filefcb[tempnode].file_start,j=1;jfilefcb[tempnode].file_length ) count= filefcb[tempnode].file_length-start; Read_Block(i,rw_buffer);
if(start+count>filefcb[tempnode].file_length )
count= filefcb[tempnode].file_length-start; if(count
for(j=0;j
dspnum=(count-(FsSupBlk.fs_blocksize-offset))/FsSupBlk.fs_blocksize+1; for(j=0;j
}
/*************************显示帮助*******************************/
void display_help()
{
-27- { } i=fat_buffer[i]; Read_Block(i,rw_buffer); x=(count-(FsSupBlk.fs_blocksize-offset))%FsSupBlk.fs_blocksize; for(j=0;j
}
printf(" 删除文件 df filename \n"); printf(" 建立文件 cf filename size \n"); printf(" 显示文件 dir \n"); printf(" 磁盘格式化 format \n"); printf(" 退出文件系统 quit \n\n");
/*************************命令解释*******************************/
void CmdShell() //全部命令的解释执行过程
{
-28- int j; int parameter; // 记录命令行参数个数 int len; // 输入的命令行长度 char string[50]; // 输入的命令行字符串 char *str[4]; // 分解出的命令行参数 bool flag; // 标志 cout
while(1)
{ printf("c:\>"); //输出系统提示符
gets(string);
len = strlen(string);
//命令行信息的解析过程
for(parameter = 0, flag = true, j = 0; j
if(string[j] == ' ') //读到输入字符为空格时,输出回车
{ flag = true; string[j] = '\0'; }
else
if(flag) { flag = false;
str[parameter++] = &string[j]; //分解出的命令,以空格为各参数
} 的分割符 } //第一个为操作命令,其他为参数
if(!strcmp("cf",str[0])) // 创建文件
strlwr(str[0]); // 根据操作命令执行不同的过程 { -29-
if(parameter != 3) printf(" 格式不正确,请重新输入 ! \n "); else create(str[1],atol(str[2])); } // 创建一个名字为str[0]大小为str[2]的文件 else if(!strcmp("df",str[0])) // 删除文件
{ if(parameter != 2) printf(" 格式不正确,请重新输入 ! \n ");
else
//disfat();} del(str[1]); } //删除文件str[1]
else if(!strcmp("dir",str[0])) //显示文件命令
dir();
else if(!strcmp("help",str[0]))
display_help();
else if(!strcmp("format",str[0]))
format(); else if(!strcmp("wf",str[0])) //写文件 { if(parameter != 3) printf(" 格式不正确,请重新输入 ! \n ");
else
write(str[1],atol(str[2])); } else if(!strcmp("rf",str[0])) //读文件内容 { if(parameter != 4) printf(" 格式不正确,请重新输入 !\n");
else
read(str[1],atol(str[2]),atol(str[3])); } -30-
else if(!strcmp("quit",str[0])) //退出 { SaveFat(); fclose(fsPtr); exit(0);}
else
}
/************************* 主过程 *******************************/
void main()
{
block_size=512; // 物理块大小512字节 } if (parameter >0 ) cout
total_disk_size=4096; // 磁盘总容量为4096块
total_dir_size=16; // 目录占有的物理块数为16块
Sys_Init(); //初始化磁盘系统 CmdShell(); //命令解释过程 total_fat_size=32; // FAT占有的物理块数为32块
}
五、实验过程原始记录(数据、图表、计算等)
六、实验结果、分析和结论(误差分析与数据处理、成果总结等。其中,绘制曲线图时必须用计算纸)
通过这次实验,我知道了文件管理的任务是对用户文件和系统文件进行管理,方便用户的使用,并保证文件的安全性。文件管理的主要目标是提高外存储空间的利用率,并能有助于提高文件系统的工作速度,还有让我知道了文件目录中为了实现文件的按名存取,每个文件应该具有一定文件名与之对应。文件的类型有系统文件、用户文件、库文件还让我学到了旋转调度采用的是延迟时间最短者优先算法,旋转调度总是对先到达磁头位置上的扇区进行信息传送操作,若访问的扇区号相同,则应分多次进行旋转调度。
同时还让我知道了磁道的驱动调度算法还有移臂调度,移臂调度中的算法有先来先服务调度算法、最短寻道时间优先调度算法、扫描算法。先来先服务调度算法只需对访问磁道的作业排队。新来的访问者排在队尾,始终从队首取出访问磁盘,直到队列为空。最短寻道时间优先调度算法,需要为请求访问磁盘的作业设置一个队列,随着当前磁道的改变,不断计算后续访问者与当前磁道的距离,让距离最的访问者访问磁盘。当前磁盘为最新访问的磁道。扫描算法需要为访问者设置两个队列,根据磁头的移动方向,能先访问的访问者由近及远排队,背离磁头移动方向者叶由近及远排为另一队。先按磁头移动方向队列调度访问者访问磁盘,当该方向没有访问者时,再改变方向,选择另一个访问者队列访问磁盘。
昆明理工大学信息工程与自动化学院学生实验报告
( 201 —201 学年 第 二 学期 )
课程名称:操作系统 开课实验室: 年 月 日
一、实验目的
用C或C++语言编写和调试一个简单的文件系统,模拟文件管理的基本功能。从而对各种文件操作命令的实质内容和执行过程有比较深入的了解。
二、实验原理及基本技术路线图(方框原理图)
用C模拟实现文件系统的管理;要求设计一个多级目录结构的文件系统,能正确描述文件控制块,采用合理的外存分配方式,能实现基本的目录及文件的操作,包括创建、删除、重命名、复制、移动等功能,并对文件有一定的存取权限控制。
功能设计 :
Help dir exit create [文件名] cdir [目录名] read [文件名] close[文件名] edit [文件名] cd [目录名] attr [文件名] del [文件名] rename [文件名] 显示命令帮助 显示当前目录下的文件和文件夹 退出系统 创建文本文件 创建文件夹 读取一个文件最多可同时读取五个 关闭一个文件 编辑一个文件 进子目录或者上级目录 显示该文件的属性 删除文件 重命名
编辑功能流程图
删除文件流程图 创建文件流程图
核心算法:
bool Format(void); //格式化 bool install(void); //装载虚拟硬盘的数据 void login(void); /用户登陆
void showMenu(void);//显示功能菜单 bool onAction(void);//用户选择功能并执行 void createFile(string str);//创建文件 bool read(string str);//读取文件 void editFile(string str);//编辑文件 void Delete(string str);//删除一个文件
数据结构:
始地址
/*inode结构体*/ struct inode{ unsigned short di_tag; /*inode标识*/
/*关联文件数,当为0时表示删除文件,如一个目录至少
包含两个文件:"."和".."*/ const unsigned int ACCOUNT_NUM=10; //用户数量 /*---------常变量------*/ const unsigned int BLOCK_SIZE=512; //块长 const unsigned int DATA_BLOCK_NUM=512; //数据块数量 const unsigned int DINODE_START=4*BLOCK_SIZE; //inode起始位置 const unsigned int DINODE_SIZE=512; const unsigned int DINODE_NUM=32; //inode大小 //inode数量 const unsigned int DATASTART=(2+DINODE_NUM)*BLOCK_SIZE; //数据区的开 unsigned short di_number;
unsigned short di_mode; /*存取模式:0为目录,1为文件*/
unsigned short di_userID; /*当前inode所属用户 0为根目录ID,一次下去是管理员目
录、用户目录*/ unsigned short di_access; /*访问权限 0为不允许普通用户访问(公共目录),1为允许 普通用户访问*/
};
unsigned short di_size; /*文件大小,目录没有大小,值为0*/ unsigned short di_ctime; /* 创建时间 */ unsigned short di_mtime; /* 最后一次修改时间*/ unsigned short di_block[DATA_BLOCK_NUM]; /* 数据块块地址编号 */
/**超级块***/
struct super_block{
};
/**账户信息**/
struct user{
};
/**文件/目录结构**/
struct directory{
unsigned short s_inodes_count; /* 文件系统中inode的总数 */ unsigned short s_blocks_count; /* 数据块总数 */ unsigned short s_r_blocks_count; /* 保留块总数 */ unsigned short s_free_blocks_count; // 空闲块总数 unsigned short s_free_inodes_count; /* 空闲的inode总数 */ unsigned short s_log_block_size; /* block 的大小 */ unsigned short user_id; //用户ID unsigned short user_access; //权限 string username; string password; //用户名 //密码
};
string name; /*目录名*/ unsigned short d_ino; /*目录号*/
三、所用仪器、材料(设备名称、型号、规格等)。
计算机一台
四、实验方法、步骤
#include
#include
#include
#include
struct OpenFileTable
{
long offset;
char file_name[10];
long int file_start;
long int file_length;
};
struct FCB_Block
{
int flag; //打开文件表数据结构 // 当前文件读写指针 // 文件名数组 // 文件起始块号 // 文件长度(字节) //FCB数据结构 // 标志,-1表示未用,1表示文件用
char file_name[10]; // 文件名数组 long int file_date; // 文件建立日期
long int file_time; // 文件建立时间
};
struct Super_Block // 超级块数据结构, 文件系统的分区信息,存放在0#物理块中
{
unsigned long int fs_totalsize; // 整个分区的总磁盘物理块数 unsigned long int fs_freesize; // 分区的所有空闲磁盘物理块数 unsigned int fs_blocksize; // 文件系统的物理块大小(字节) unsigned int fs_fat_start; // FAT的起始磁盘物理块号 unsigned int fs_fat_size; // FAT占用的磁盘物理块数 unsigned int fs_dir_start; // 根目录的起始磁盘物理块号 unsigned int fs_dir_size; // 根目录占用的磁盘物理块数 unsigned int fs_data_start; // 数据区起始磁盘物理块号 unsigned long int fs_data_size; // 数据区的磁盘物理块数 long int file_start; // 文件起始块号 long int file_length; // 文件长度(字节)
};
const char DiskName[]="FileSys.dat"; //磁盘文件名
char rw_buffer[512]; // 读写使用的缓冲区
struct FCB_Block filefcb[130]; // 读写目录使用的数据结构
struct Super_Block FsSupBlk; // 读写超级块使用的数据结构
long int fat_buffer[5000]; // 读写FAT使用的缓冲区,为简化在系统启动时全部装入内存,0为空闲
struct OpenFileTable OFT[16]; // 打开文件表,当前只使用OFT[0]
unsigned int block_size; // 物理块大小(字节)
unsigned long int total_disk_size; // 磁盘总容量(物理块数)
unsigned int total_dir_size; // 目录占有的物理块数
unsigned int total_fat_size; // FAT占有的物理块数
long int find_fcb; // 记录读FCB块的次数
FILE *fsPtr; // 模拟磁盘的文件指针
/*********************** 磁盘块的申请***********************************/
unsigned long int Get_Block(unsigned long int count) //分配count个物理快,返回首块指针,其它已经连接
{
unsigned long int tmp,firstblk,tmpcount; unsigned long int i;
int flag=1;
if (count > FsSupBlk.fs_freesize)
{ printf(" ==== 没有足够磁盘容量,不能分配!==== \n"); return 0; }
tmpcount=0;
for(i=FsSupBlk.fs_data_start;i
}
/*********************** 磁盘块的回收***********************************/
void Put_Block(unsigned long int addr)
{ unsigned long int i,j;
{ if(fat_buffer[i] == 0) //文件未占有,分配 { if (flag==1) { firstblk=i; flag=-1;} else { fat_buffer[tmp]=i; } } tmp=i; fat_buffer[i]=-1; tmpcount++; } if(tmpcount==count) //分配完成 { FsSupBlk.fs_freesize=FsSupBlk.fs_freesize-count;//减少可分配物理块 return firstblk; } return -1; //分配不成功
int count;
i=addr; count=0;
while(fat_buffer[i]!=-1)
{ j=fat_buffer[i]; //下一项
fat_buffer[i] = 0;
fat_buffer[i] = 0;
FsSupBlk.fs_freesize=FsSupBlk.fs_freesize+count+1;//增加可分配物理块
return;
}
/*********************** 读磁盘块***********************************/
void Read_Block(unsigned long int addr,char *buf)
{
fseek(fsPtr,FsSupBlk.fs_blocksize*addr,SEEK_SET); if (addr>FsSupBlk.fs_totalsize) { printf(" ==== 超出磁盘容量,不能读!==== \n"); return; } count++; i=j; }
fread(buf,512,1,fsPtr);
}
return;
/*********************** 写磁盘块***********************************/
void Write_Block(unsigned long int addr,char *buf)
{
fseek(fsPtr,FsSupBlk.fs_blocksize*addr,SEEK_SET); if (addr>FsSupBlk.fs_totalsize) { printf(" ==== 超出磁盘容量,不能写!==== \n"); return; }
fwrite(buf,512,1,fsPtr);
}
/*********************** 格式化磁盘***********************************/
void Real_Format()
{
unsigned long int bcount; return;
long int fatval,i;
//更改系统超级块信息 char *c;
FsSupBlk.fs_totalsize=total_disk_size;
FsSupBlk.fs_blocksize=block_size;
FsSupBlk.fs_dir_start=1;
FsSupBlk.fs_dir_size=total_dir_size;
FsSupBlk.fs_fat_start=total_dir_size+1;
-11-
FsSupBlk.fs_fat_size=total_fat_size;
FsSupBlk.fs_data_start=FsSupBlk.fs_fat_start+FsSupBlk.fs_fat_size;
FsSupBlk.fs_data_size
FsSupBlk.fs_fat_size-1;
FsSupBlk.fs_freesize= FsSupBlk.fs_data_size;
//初始化FAT //初始化目录 for(i=0;i
fatval=FsSupBlk.fs_fat_start*512;
fseek(fsPtr,fatval,SEEK_SET); //定位文件指针
bcount=FsSupBlk.fs_fat_size+FsSupBlk.fs_dir_size+1; for(i=0;i
-12- for(;i
} //初始化数据区 for(i=0;i
/***********************新建系统磁盘文件
***********************************/
void Create_Disk()
{
// 建立磁盘文件
total=total_disk_size;
for(i=0;i
-13- long int i; unsigned long int total; fsPtr=fopen(DiskName,"wb+"); if(fsPtr==NULL) { } printf(" 不能建立磁盘所需的文件 !\n"); exit(0);
fwrite(rw_buffer,512,1,fsPtr);
fclose(fsPtr);
fsPtr=fopen(DiskName,"rb+");
Real_Format();
return;
}
/***********************读写系统超级块信息
***********************************/
void Read_Boot() //读取磁盘超级块数据信息
{
rewind(fsPtr);
}
void FileBoot() //超级块数据信息存盘
{
rewind(fsPtr);
fread(&FsSupBlk,sizeof(struct Super_Block),1,fsPtr); return; fwrite(&FsSupBlk,sizeof(struct Super_Block),1,fsPtr); return; -14-
}
/***********************FAT操作***********************************/
void LoadFat() //装载全部FAT到内存
{
fseek(fsPtr,FsSupBlk.fs_fat_start*512,SEEK_SET);
}
void SaveFat() //FAT到文件FAT区
{
}
/***********************显示超级块信息***********************************/ void boot_dis()
{
printf("FsSupBlk.fs_totalsize=%ld\n",FsSupBlk.fs_totalsize);
printf("FsSupBlk.fs_blocksize=%d\n",FsSupBlk.fs_blocksize);
printf("FsSupBlk.fs_dir_start=%d\n",FsSupBlk.fs_dir_start);
printf("FsSupBlk.fs_dir_size=%d\n",FsSupBlk.fs_dir_size);
-15- fread(fat_buffer,sizeof(long int),FsSupBlk.fs_totalsize ,fsPtr); return; fseek(fsPtr,FsSupBlk.fs_fat_start*512,SEEK_SET); fwrite(fat_buffer,sizeof(long int),FsSupBlk.fs_totalsize,fsPtr); return;
printf("FsSupBlk.fs_fat_start=%d\n",FsSupBlk.fs_fat_start);
printf("FsSupBlk.fs_fat_size=%d\n",FsSupBlk.fs_fat_size);
printf("FsSupBlk.fs_data_start=%d\n",FsSupBlk.fs_data_start);
printf("FsSupBlk.fs_data_size=%ld\n",FsSupBlk.fs_data_size);
printf("FsSupBlk.fs_freesize=%ld\n",FsSupBlk.fs_freesize);
}
/***********************系统初始化***********************************/
void Sys_Init() //初始化
{
Read_Boot();
//boot_dis(); fsPtr=fopen(DiskName,"rb+"); if(fsPtr == NULL) Create_Disk();
LoadFat();
}
/***********************显示操作***********************************/
void dir() //显示目录下的文件
{
int i,countFile=0; return;
char str[16];
long int n,pos_dir,pos_fat;
-16-
pos_dir=FsSupBlk.fs_dir_start*512;
pos_fat=FsSupBlk.fs_fat_start*512;
fseek(fsPtr,pos_dir,SEEK_SET); while(ftell(fsPtr)
for(i=0;i
if(filefcb[i].flag == 1) //文件占有
{ countFile++;
n = filefcb[i].file_length;
printf(" %-15s%15d bytes\n", filefcb[i].file_name,"file",n);
}
/*************************查找文件*******************************/
//查找文件,文件存在返回当前FCB数组下标,否则返回-1
-17- } } cout
int Find_File(char *filename)
{
int i; long int pos_dir,pos_fat;
pos_dir=FsSupBlk.fs_dir_start*512;
pos_fat=FsSupBlk.fs_fat_start*512;
find_fcb=0;
fseek(fsPtr,pos_dir,SEEK_SET); while(ftell(fsPtr)
for(i=0;i
if(filefcb[i].flag!=-1)
{ if(strcmp(filename,filefcb[i].file_name) == 0) return i;} //文件存在
return -1;
}
/*************************创建文件*******************************/
void create(char *fname,long int num) //在当前目录下创建一个名字为str的文件,长度为num
{
int i,j; //true表示没有与该名字重名的文件
int tempnode;
-18- }
long int pos_dir,getnum=0; unsigned long int blkcount; blkcount= num/512+1; //计算需要的物理块
if(FsSupBlk.fs_freesize
// 建立文件的处理 if (tempnode!=-1) //表示文件存在 { printf("\n 文件已经存在,不需要建立 !\n\n"); return;} tempnode=Find_File(fname); { } printf("\n 磁盘没有足够空间,不能建立 !\n\n"); return;
pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize;
fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区 for(i=0; i
if(filefcb[j].flag == -1) //找到空目录项 {
}
} // 分配空间, 标记FCB数据项,并将FCB写磁盘 getnum=Get_Block(blkcount); if(getnum==-1){ printf("不能分配存储空间 \n");return;} filefcb[j].file_start=getnum; filefcb[j].flag = 1; filefcb[j].file_length=num; strcpy(filefcb[j].file_name,fname); //filefcb[].file_time= //filefcb[].file_date= // 改变磁盘FCB值 pos_dir=pos_dir+sizeof(struct FCB_Block)*(i*16+j); fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区的FCB项fwrite(&filefcb[j],sizeof(struct FCB_Block),1 ,fsPtr); //Write_Block(i+FsSupBlk.fs_dir_start,(char *)filefcb); printf(" 文件占用了 %d 个物理块\n",blkcount); printf(" 系统还有 %ld 个物理块可用\n\n",FsSupBlk.fs_freesize); return;
-20-
//没有FCB项,不能建立文件
cout
return;
}
/*************************格式化*******************************/
void format()
{
char ch;
cout
cin>>ch;
if(ch=='y'||ch=='Y')
}
/****************************删除文件操作
**************************************/
void del(char *fname)
{
{ Real_Format(); printf("\n Format Successful!\n\n"); } long int tempnode; long int pos_dir; -21-
// 删除文件的处理 tempnode=Find_File(fname); if (tempnode==-1) //表示文件不存在 { printf("\n 文件不存在,不能删除 !\n\n"); return;}
Put_Block(filefcb[tempnode].file_start); // 释放文件存储空间
filefcb[tempnode].flag =-1; // 标记FCB项可用
// 修改的FCB项写回磁盘 pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize+((find_fcb-1)*16+tempnode)*sizeof(struct FCB_Block);
}
/*************************写文件*******************************/
void write(char *fname ,int num)//写文件,仅实现在文件尾部填加内容,并限制在512个字节内
{
int tempnode;
int i,j,x;
-22- fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区 fwrite(&filefcb[tempnode],sizeof(struct FCB_Block),1 ,fsPtr); return;
long int pos_dir;
rescount=filefcb[tempnode].file_length % FsSupBlk.fs_blocksize; char *string=new char [num]; //申请空间 for(i=0;i 512) { } tempnode=Find_File(fname); if (tempnode==-1) //表示文件不存在 { } // 写文件的处理 printf("\n 文件不存在,不能写 !\n\n"); return; printf("\n 不能写大于512字节的数据 !\n\n"); return; cin>>string[i]; }
if (num> FsSupBlk.fs_blocksize-rescount)
{ if (FsSupBlk.fs_freesize
} } printf("\n 文件系统没有足够空间,不能写 !\n\n"); return; for(j=filefcb[tempnode].file_start;fat_buffer[j]!=-1;j=fat_buffer[j]); Read_Block(j,rw_buffer);
if (num
{ } else { for(i=0;i
for(i=0;i
rw_buffer[rescount+i]=string[i]; Write_Block(j,rw_buffer);
fat_buffer[j]=Get_Block(1);
j=fat_buffer[j];
for(x=0;x
for(x=0;x
rw_buffer[x]=string[i+x]; Write_Block(j,rw_buffer); }
//delete []string;
-24-
// 修改FCB项并写回磁盘
filefcb[tempnode].file_length+=num; // 增加文件的长度
pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize+((find_fcb-1)*16+tempnode)*sizeof(struct FCB_Block);
fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区 fwrite(&filefcb[tempnode],sizeof(struct FCB_Block),1 ,fsPtr);
cin.ignore(10000,'\n'); //清除输入流缓冲区
}
void copyFcbtoOft(int fcbpos)
{
OFT[0].offset =0; strcpy(OFT[0].file_name,filefcb[fcbpos].file_name); cout
OFT[0].file_start = filefcb[fcbpos].file_start ;
OFT[0].file_length= filefcb[fcbpos].file_length ;
}
/*************************读文件*******************************/
void read(char *fname,long start,int count)//读文件 ,限制在512个字节内
{
int tempnode;
int stblknum,offset; -25- int dspnum;
tempnode=Find_File(fname); if (tempnode==-1) //表示文件不存在 { printf("\n 文件不存在,不能读 !\n\n"); return; } if (start > filefcb[tempnode].file_length) //读的数据超出文件范围 { printf("\n 超出文件范围,不能读 !\n\n"); return; } // 读文件的处理
printf("\n========================================\n");
stblknum=start/FsSupBlk.fs_blocksize+1; // 起始物理块
offset=start%FsSupBlk.fs_blocksize; // 起始物理块的偏移量
for(i=filefcb[tempnode].file_start,j=1;jfilefcb[tempnode].file_length ) count= filefcb[tempnode].file_length-start; Read_Block(i,rw_buffer);
if(start+count>filefcb[tempnode].file_length )
count= filefcb[tempnode].file_length-start; if(count
for(j=0;j
dspnum=(count-(FsSupBlk.fs_blocksize-offset))/FsSupBlk.fs_blocksize+1; for(j=0;j
}
/*************************显示帮助*******************************/
void display_help()
{
-27- { } i=fat_buffer[i]; Read_Block(i,rw_buffer); x=(count-(FsSupBlk.fs_blocksize-offset))%FsSupBlk.fs_blocksize; for(j=0;j
}
printf(" 删除文件 df filename \n"); printf(" 建立文件 cf filename size \n"); printf(" 显示文件 dir \n"); printf(" 磁盘格式化 format \n"); printf(" 退出文件系统 quit \n\n");
/*************************命令解释*******************************/
void CmdShell() //全部命令的解释执行过程
{
-28- int j; int parameter; // 记录命令行参数个数 int len; // 输入的命令行长度 char string[50]; // 输入的命令行字符串 char *str[4]; // 分解出的命令行参数 bool flag; // 标志 cout
while(1)
{ printf("c:\>"); //输出系统提示符
gets(string);
len = strlen(string);
//命令行信息的解析过程
for(parameter = 0, flag = true, j = 0; j
if(string[j] == ' ') //读到输入字符为空格时,输出回车
{ flag = true; string[j] = '\0'; }
else
if(flag) { flag = false;
str[parameter++] = &string[j]; //分解出的命令,以空格为各参数
} 的分割符 } //第一个为操作命令,其他为参数
if(!strcmp("cf",str[0])) // 创建文件
strlwr(str[0]); // 根据操作命令执行不同的过程 { -29-
if(parameter != 3) printf(" 格式不正确,请重新输入 ! \n "); else create(str[1],atol(str[2])); } // 创建一个名字为str[0]大小为str[2]的文件 else if(!strcmp("df",str[0])) // 删除文件
{ if(parameter != 2) printf(" 格式不正确,请重新输入 ! \n ");
else
//disfat();} del(str[1]); } //删除文件str[1]
else if(!strcmp("dir",str[0])) //显示文件命令
dir();
else if(!strcmp("help",str[0]))
display_help();
else if(!strcmp("format",str[0]))
format(); else if(!strcmp("wf",str[0])) //写文件 { if(parameter != 3) printf(" 格式不正确,请重新输入 ! \n ");
else
write(str[1],atol(str[2])); } else if(!strcmp("rf",str[0])) //读文件内容 { if(parameter != 4) printf(" 格式不正确,请重新输入 !\n");
else
read(str[1],atol(str[2]),atol(str[3])); } -30-
else if(!strcmp("quit",str[0])) //退出 { SaveFat(); fclose(fsPtr); exit(0);}
else
}
/************************* 主过程 *******************************/
void main()
{
block_size=512; // 物理块大小512字节 } if (parameter >0 ) cout
total_disk_size=4096; // 磁盘总容量为4096块
total_dir_size=16; // 目录占有的物理块数为16块
Sys_Init(); //初始化磁盘系统 CmdShell(); //命令解释过程 total_fat_size=32; // FAT占有的物理块数为32块
}
五、实验过程原始记录(数据、图表、计算等)
六、实验结果、分析和结论(误差分析与数据处理、成果总结等。其中,绘制曲线图时必须用计算纸)
通过这次实验,我知道了文件管理的任务是对用户文件和系统文件进行管理,方便用户的使用,并保证文件的安全性。文件管理的主要目标是提高外存储空间的利用率,并能有助于提高文件系统的工作速度,还有让我知道了文件目录中为了实现文件的按名存取,每个文件应该具有一定文件名与之对应。文件的类型有系统文件、用户文件、库文件还让我学到了旋转调度采用的是延迟时间最短者优先算法,旋转调度总是对先到达磁头位置上的扇区进行信息传送操作,若访问的扇区号相同,则应分多次进行旋转调度。
同时还让我知道了磁道的驱动调度算法还有移臂调度,移臂调度中的算法有先来先服务调度算法、最短寻道时间优先调度算法、扫描算法。先来先服务调度算法只需对访问磁道的作业排队。新来的访问者排在队尾,始终从队首取出访问磁盘,直到队列为空。最短寻道时间优先调度算法,需要为请求访问磁盘的作业设置一个队列,随着当前磁道的改变,不断计算后续访问者与当前磁道的距离,让距离最的访问者访问磁盘。当前磁盘为最新访问的磁道。扫描算法需要为访问者设置两个队列,根据磁头的移动方向,能先访问的访问者由近及远排队,背离磁头移动方向者叶由近及远排为另一队。先按磁头移动方向队列调度访问者访问磁盘,当该方向没有访问者时,再改变方向,选择另一个访问者队列访问磁盘。