课程名称计算机操作系统实验名称文件系统存储空间管理模拟姓名学号专业班级实验日期成绩指导老师一、实验目的根据提出的文件分配和释放请求,动态显示磁盘空闲空间的态以及文件目录的变化,以位示图和索引分配为例:每次执行请求后要求显示或打印位示图的修改位置、分配和回收磁盘的物理块地址、更新的位示图、目录。
二、实验原理用数组表示位示图,其中的每一位对应磁盘一个物理块的状态,0表示、空闲,1表示分配;当请求分配一个磁盘块时,寻找到数组中为0的位,计算相对磁盘块号,并计算其在磁盘中的物理地址(柱面号、磁道号、物理块号),并将其状态由0变到1。
当释放某一物理块时,已知其在磁盘中的物理地址,计算其相对磁盘块号,再找到位示图数组中的相应位,将其状态由1变为0。
三、主要仪器设备PC机(含有VC)四、实验容与步骤实验容:1. 模拟文件空间分配、释放过程,可选择连续分配、链式分配、索引分配法;2. 文件空闲空间管理,可采用空白块链、空白目录、位示图法;步骤如下:1. 输入磁盘基本信息参数,计算位示图大小,并随机初始化位示图;(1)磁盘基本信息:磁盘柱面数m, 每柱面磁道数p, 每磁道物理块数q;(2)假设采用整数数组存放位示图,则数组大小为:Size= ceil((柱面数*每柱面磁道数*每磁道物理块数)/(sizeof(int)*8))(3)申请大小为size的整数数组map,并对其进行随机初始化。
例如:假设m=2, p=4, q=8, 共有64个磁盘块,若sizeof(int)=2, 则位示图大小为4,map[4]如下:地址到高地址位上。
即map[0]的第0位到第15位分别对应0号磁盘块到15号磁盘块的状态,map[1]的第0位到第15位对应16号磁盘块到31号磁盘块的状如上表所示,29号磁盘的状态存在map[1]中,对应于第13位;2. 输出初始位示图信息;3. 输入文件分配或释放请求,(1)格式:“+ 文件名申请块数”或“- 文件名”“+”表示申请文件分配,“-”表示删除文件如:+ F1 54. 根据请求完成相应操作。
(1)若为分配申请x个盘块,则在位示图中找到x个为0的位,将其修改为“1”,计算相应具体物理设备的柱面号C、磁道号H和物理块号R,并将CHR 地址或相对磁盘块号记录在文件目录中。
输出位示图修改位置、分配的磁盘块CHR地址、修改后的目录和位示图信息。
否则,空间不够,退出执行下一条请求;●计算公式如下:a. 已知位示图中的下标i , j, 计算相对块号Block= i*sizeof( int )*8+jb. 已知相对块号计算柱面、磁道、物理块号如下:柱面号C= 相对块号/(每柱面磁道数*每磁道物理块数)磁道号H= 相对块号%(每柱面磁道数*每磁道物理块数)/ 每磁道物理块数物理块号R= 相对块号%每磁道物理块数●(2)若为删除申请,则从目录中找到要删除的文件所在的目录项,读取索引表,依次读取文件相应的盘块CHR地址, 计算该盘块的相对磁盘块号,再计算其相应信息在位示图中的位置( i,j),将位示图中的相应位有“1”改为“0”,并从目录中删除该目录项。
输出删除的磁盘块CHR地址、相应位示图修改位置、修改过的位示图和目录。
计算过程如下:相对磁盘块号= 柱面号*每柱面磁道数*每磁道物理块数+磁道号*每磁道物理块数+ 物理块号i = 相对磁盘块号/ (sizeof(int)*8)j = 相对磁盘块号% (sizeof(int)*8)五、实验流程图图一文件空闲区分配算法图二文件空闲区回收算法六、实验代码#include "stdio.h"#include <stdlib.h>#include <conio.h>#include <string.h>int physic[100]; //文件地址缓冲区int style=1; //文件的类型char cur_dir[10]="root"; //当前目录struct command{char [10];}cmd[13];struct block{ int n; //空闲的盘快的个数int free[50]; //存放空闲盘快的地址int a; //模拟盘快是否被占用}memory[20449];struct block_super{int n; //空闲的盘快的个数int free[50]; //存放进入栈中的空闲块int stack[50]; //存放下一组空闲盘快的地址}super_block;struct node //i结点信息{int file_style; //i结点文件类型int file_length; //i结点文件长度int file_address[100]; //i结点文件的物理地址} i_node[640];struct dir //目录项信息{char file_name[10]; //文件名int i_num; //文件的结点号char dir_name[10]; //文件所在的目录} root[640];void format() //格式化{int i,j,k;super_block.n=50;for(i=0;i<50;i++) //超级块初始化{ super_block.free[i]=i; //存放进入栈中的空闲块super_block.stack[i]=50+i; //存放下一组的盘块}for(i=0;i<640;i++) //i结点信息初始化{for(j=0;j<100;j++){i_node[i].file_address[j]=-1;//文件地址}i_node[i].file_length=-1; //文件长度i_node[i].file_style=-1; //文件类型}for(i=0;i<640;i++) //根目录区信息初始化{strcpy(root[i].file_name,"");root[i].i_num=-1;strcpy(root[i].dir_name,"");}for(i=0;i<20449;i++) //存储空间初始化{memory[i].n=0; //必须有这个memory[i].a=0;for(j=0;j<50;j++){memory[i].free[j]=-1;}for(i=0;i<20449;i++) //将空闲块的信息用成组的法写进每组的最后一个块中{ //存储空间初始化if((i+1)%50==0){k=i+1;for(j=0;j<50;j++){if(k<20450){memory[i].free[j]=k;//下一组空闲地址memory[i].n++; //下一组空闲个数注意在memory[i].n++之前要给其赋初值k++;}else{memory[i].free[j]=-1;}}memory[i].a=0; //标记为没有使用continue; //处理完用于存储下一组盘块信息的特殊盘块后,跳过本次循环}for(j=0;j<50;j++){memory[i].free[j]=-1;}memory[i].n=0;}printf("已经初始化完毕\n");printf("进入UNIX文件模拟............\n\n");}void write_file(FILE *fp) //将信息读入系统文件中{int i;fp=fopen("system","wb");for(i=0;i<20449;i++){ fwrite(&memory[i],sizeof(struct block),1,fp);}fwrite(&super_block,sizeof(struct block_super),1,fp);for(i=0;i<640;i++){write(&i_node[i],sizeof(struct node),1,fp);}for(i=0;i<640;i++){ fwrite(&root[i],sizeof(struct dir),1,fp);}fclose(fp);}void read_file(FILE *fp) //读出系统文件的信息{ int i;fp=fopen("system","rb");for(i=0;i<20449;i++){fread(&memory[i],sizeof(struct block),1,fp);}fread(&super_block,sizeof(struct block_super),1,fp);for(i=0;i<640;i++){ fread(&i_node[i],sizeof(struct node),1,fp);}for(i=0;i<640;i++){fread(&root[i],sizeof(struct dir),1,fp);}fclose(fp);}void callback(int length) //回收磁盘空间{ int i,j,k,m,q=0;for(i=length-1;i>=0;i--)k=physic[i]; //需要提供要回收的文件的地址m=49-super_block.n; //回收到栈中的哪个位置if(super_block.n==50) //注意当super_block.n==50时m=-1;的值{ //super_block.n==50的时候栈满了,要将这个栈中的所有地址信息写进下一个地址中for(j=0;j<50;j++){memory[k].free[j]=super_block.free[j];}super_block.n=0;memory[k].n=50;}memory[k].a=0;if(m==-1){ m=49; //将下一个文件地址中的盘块号回收到栈底中,这个地址中存放着刚才满栈的地址的信息}super_block.free[m]=physic[i]; //将下一个文件地址中的盘块号回收到栈中super_block.n++;}}void allot(int length) //分配空间{ int i,j,k,m,p;for(i=0;i<length;i++){k=50-super_block.n; //超级块中表示空闲块的指针m=super_block.free[k]; //栈中的相应盘块的地址p=super_block.free[49]; //栈中的最后一个盘块指向的地址if(m==-1||memory[p].a==1) //检测是否还有下一组盘块{printf("存不足,不能够分配空间\n");callback(length);break;}if(super_block.n==1){memory[m].a=1; //将最后一个盘块分配掉physic[i]=m;super_block.n=0;for(j=0;j<memory[m].n;j++) //从最后一个盘块中取出下一组盘块号写入栈中{super_block.free[j]=memory[m].free[j];super_block.n++;}continue; //要跳过这次循环,下面的语句在IF中已经执行过}physic[i]=m; //栈中的相应盘块的地址写进文件地址缓冲区memory[m].a=1;super_block.n--;}}void create_file(char filename[],int length) //创建文件{int i,j;for(i=0;i<640;i++){if(strcmp(filename,root[i].file_name)==0)printf("文件已经存在,不允建立重名的文件\n");return;}}for(i=0;i<640;i++){if(root[i].i_num==-1){root[i].i_num=i;strcpy(root[i].file_name,filename);strcpy(root[i].dir_name,cur_dir); //把当前目录名给新建立的文件i_node[i].file_style=style;i_node[i].file_length=length;allot(length);for(j=0;j<length;j++){i_node[i].file_address[j]=physic[j];}break;}}}void create_dir(char filename[]) //创建目录{style=0; //0代表文件类型是目录文件create_file(filename,4);style=1; //用完恢复初值,因为全局变量,否则}void del_file(char filename[]) //删除文件{int i,j,k;for(i=0;i<640;i++){if(strcmp(filename,root[i].file_name)==0){k=root[i].i_num;for(j=0;j<i_node[k].file_length;j++){physic[j]=i_node[k].file_address[j];}callback(i_node[k].file_length); //调用回收函数for(j=0;j<100;j++) //删除文件后要将文件属性和目录项的各个值恢复初值{i_node[k].file_address[j]=-1; //地址恢复初值}strcpy(root[i].file_name,""); //文件名恢复初值root[i].i_num=-1; //目录项的I结点信息恢复初值strcpy(root[i].dir_name,""); //目录项的文件目录信息恢复初值i_node[k].file_length=-1; //文件长度恢复i_node[k].file_style=-1; //文件类型恢复初值break;}}if(i==640){printf("不存在这个文件\n");}}void del_dir(char filename[]) //删除目录需要判断目录下时候为空,不为空就不删除int i,j,k;for(i=0;i<640;i++) //还要加条件判断要删除的目录是不是当前目录{k=root[i].i_num; //找到目录名字if( strcmp(root[i].file_name,filename)==0 && strcmp(cur_dir,filename)!=0 && (i_node[k].file_style)==0 ){for(j=0;j<640;j++){if(strcmp(filename,root[j].dir_name)==0){printf("目录不为空不能直接删除\n");break;}}if(j==640){del_file(filename);break;}break;}}if(i==640){printf("这个不是目录文件或者不存在这个目录,或者你要删除的是当前目录\n");}}void display_curdir() //显示当前目录下的文件列表{int i,k;printf("\t\t文件名字文件类型文件长度所属目录\n");for(i=0;i<640;i++){if(strcmp(cur_dir,root[i].dir_name)==0) //查询文件中所在目录信息和当前目录信息相同的数据{k=root[i].i_num;printf("\t\t %s\t",root[i].file_name); //文件名printf("\t%d\t",i_node[k].file_style); //文件的类型printf("%d\t",i_node[k].file_length); //文件的长度printf("%s\n",root[i].dir_name); //文件所在的目录}}}void display_dir(char filename[]) //进入指定的目录{int i,k;for(i=0;i<640;i++){k=root[i].i_num; //判断文件类型是不是目录类型if((strcmp(filename,root[i].file_name)==0) && (i_node[k].file_style==0)){strcpy(cur_dir,filename); //将要进入的指定目录设置为当前目录赋值不要反了strcpy(目的,源)break;}if(i==640){printf("没有这个目录\n");}}void open_file(char filename[]) //打开文件{int i,j,k;printf("\t\t文件名字文件类型文件长度所属目录\n");for(i=0;i<640;i++){k=root[i].i_num;if(strcmp(filename,root[i].file_name)==0 && (i_node[k].file_style==1)){printf("\t\t %s\t",root[i].file_name); //文件名printf("\t%d\t",i_node[k].file_style); //文件的类型printf("%d\t",i_node[k].file_length); //文件的长度printf("%s\n",root[i].dir_name); //文件所在的目录printf("\t\t文件占用的物理地址\n");for(j=0;j<i_node[k].file_length;j++) //显示物理地址{printf("%d ",i_node[k].file_address[j]); //文件具体占用的盘块号}printf("\n");break;}}if(i==640){printf("没有这个文件或者这个文件不是正规文件\n");}}void back_dir() //返回上一级目录{int i,k;for(i=0;i<640;i++) //查询和当前目录名相同的目录文件名{k=root[i].i_num;if(strcmp(cur_dir,root[i].file_name)==0 && (i_node[k].file_style==0)){strcpy(cur_dir,root[i].dir_name); //将查询到的目录文件名所在的目录赋值给当前目录}}}void display_sys() //显示系统信息(磁盘使用情况){int i,m,k=0;for(i=0;i<20449;i++){if(memory[i].a==0)k++;}m=20449-k;printf("空闲的盘块数是:\t");printf("%d\n",k);printf("使用的盘块数是:\t");printf("%d\n",m);}void help() //显示帮助信息{printf("***********************************************************\n"); printf("* 以下是文件管理已分配盘块------------------------------- *\n");printf("* 1.初始化-----------------------------------------format *\n");printf("* 2.查看当前目录文件列表---------------------------dir *\n");printf("* 3.查看文件--------------cat-----(cat + 空格+ 文件名) *\n");printf("* 4.查看系统信息-----------------------------------ls *\n");printf("* 5.创建目录--------------md------(md + 空格+ 目录名) *\n");printf("* 6.创建文件---vi------(vi + 空格+ 文件名+ 文件长度) *\n"); printf("* 7.删除文件---------------del-----(del + 空格+ 文件名) *\n");printf("* 8.删除目录----------------deldir--(del + 空格+ 目录名) *\n");printf("* 9.进入当前目录下的指定目录-----cd--(cd + 空格+ 目录名) *\n"); printf("* 10.返回上一级目录--------------------------------cd.. *\n");printf("* 11.显示帮助命令----------------------------------help *\n");printf("* 12.退出文件模拟----------------------------------quit *\n");printf("* 13,进入成组----------------------------------guo *\n");printf("***********************************************************\n"); }int MA[4]; /*空闲块数组*/int A[9][4]={{3,1,2,3},{3,4,5,6},{0,0,0,0},{0,0,0,0},{3,0,7,8},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; /*磁盘空间*/int mark[9]; /*存放已分配的块*/int No=0; /*已分配的块数*/void display1(){ int i,j,temp,count;No=0;if(MA[1]!=0){ i=MA[0];printf("\ngroup1:");for(j=1;j<=i;j++){ printf("%d ",MA[j]);mark[++No]=MA[j];}temp=MA[1];count=2;while(A[temp][1]!=0){ printf("\ngroup%d:",count);i=A[temp][0];for(j=1;j<=i;j++){ printf("%d ",A[temp][j]);mark[++No]=A[temp][j];}count++;temp=A[temp][1];}printf("\ngroup%d:",count);i=A[temp][0];for(j=2;j<=i+1;j++)if(A[temp][j]>0){ printf("%d ",A[temp][j]);mark[++No]=A[temp][j];}}elseif(i==1)printf("\nThe blocks are all assigned");else{ printf("\ngroup1:");for(j=2;j<=i;j++){ printf("%d ",MA[j]);mark[++No]=MA[j];}}}}void display() /*显示分组情况*/{ int i,j;if(MA[0]!=0)display1();else{ i=MA[1];for(j=0;j<=3;j++)MA[j]=A[i][j];display1();}}void assign() /*分配空闲块*/{ int s,i;if(MA[0]>1) /*若该组不止一个空闲块*/{ i=MA[0];s=MA[i];MA[0]--;printf("\nnumber of the block:%d",s);}else if(MA[0]==1) /*只剩一个空闲块*/{ if(MA[1]!=0) /*还有其它空闲块组*/{ s=MA[1];for(i=0;i<=3;i++)A[0][i]=A[s][i];MA[0]--;printf("\nnumber of the block:%d",s);}else /*没有其它空闲块组*/{ printf("\nThere isn't any space");return;}}else /*当前组已分配完*/{ for(i=0;i<=3;i++)MA[i]=A[0][i];assign();}display(); /*显示分组情况*/}void callback() /*回收空闲块*/{ int i,j,temp;printf("\ninput the No. of the block you want to callback:");scanf("%d",&j);getchar(); /*得到待回收的空闲块号*/for(temp=1;temp<=No;temp++){ if(mark[temp]==j)}if(temp<No+1) /*若该空闲块已在,退出*/{ printf("\nThe block is in the disk");return;}if(MA[0]<3) /*当前组不满3块*/{ i=MA[0];MA[i+1]=j;MA[0]++;}else /*已有3块*/{ for(i=0;i<=3;i++)A[j][i]=MA[i];MA[0]=1;MA[1]=j;}display(); /*显示*/}int filecontrol();void menu() /*功能选择函数*/{ int choice;char judge;printf("文件管理空间管理\n");printf("\ninput your choice:(1--assign,2--callback,3--backtofilecontrol):\n");scanf("%d",&choice);getchar();if(choice==1)assign();else if(choice==2)callback();else if(choice==3)filecontrol();elseprintf("\ninvalid command!");printf("\ncontinue or not?(y--Yes,n--Not):");scanf("%c",&judge);getchar();if(judge=='y')menu();else{ printf("\nNow the graph is:");display();printf("\npress any key to quit");getchar();}}void guolink(){ int i;for(i=0;i<=3;i++)MA[i]=A[0][i];display();menu();}int filecontrol() //主函数{ int i, j=0,p,len=0;char tmp[10],[10],tmp1[10],k;struct command tmp2[10];FILE *fp;help();strcpy(cmd[0].,"format"); //将各个命令存进命令表strcpy(cmd[1].,"dir");strcpy(cmd[2].,"cat");strcpy(cmd[3].,"ls");strcpy(cmd[4].,"md");strcpy(cmd[5].,"vi");strcpy(cmd[6].,"del");strcpy(cmd[7].,"deldir");strcpy(cmd[8].,"cd");strcpy(cmd[9].,"cd..");strcpy(cmd[10].,"help");strcpy(cmd[11].,"quit");strcpy(cmd[12].,"guo");if((fp=fopen("system","rb"))==NULL) //判断系统文件是否存在{printf("can not open file\n");printf("format the disk Y / N \n");scanf("%c",&k);if(k=='y')format();}else{read_file(fp); //读取系统文件的容}while(1){j=0; //必须重新给恢复0否则出错strcpy(tmp,cur_dir);while(strcmp(tmp,"root")!=0){for(i=0;i<640;i++){p=root[i].i_num;if(strcmp(tmp,root[i].file_name)==0 && (i_node[p].file_style==0)) {strcpy(tmp2[j].,tmp);j++;strcpy(tmp,root[i].dir_name);}}}strcpy(tmp2[j].,tmp);for(i=j;i>=0;i--){printf("%s/",tmp2[i].);}scanf("%s",); //输入命令并且查找命令的相关操作for(i=0;i<13;i++){if(strcmp(,cmd[i].)==0){p=i;break;}if(i==13) //如果没有这个语句以后输入的命令都和第一次输入的效果一样{p=14; //随便的一个值}switch(p){case 0: format(); //初始化break;case 1: display_curdir(); //查看当前目录下的文件列表break;case 2: scanf("%s",tmp); //查看文件open_file(tmp);break;case 3: display_sys(); //查看系统信息break;case 4:scanf("%s",tmp); //创建目录create_dir(tmp);break;case 5: scanf("%s",tmp); //创建文件scanf("%d",&len);create_file(tmp,len);break;case 6: scanf("%s",tmp); //删除文件for(i=0;i<640;i++) //判断文件是不是正规文件{j=root[i].i_num;if(strcmp(tmp,root[i].file_name)==0 && (i_node[j].file_style)==1){del_file(tmp);break;}}if(i==640){printf("这个不是正规文件文件\n");}break;case 7:scanf("%s",tmp); //删除目录del_dir(tmp);break;case 8: scanf("%s",tmp1); //进入当前目录下的指定目录相当于进入目录cd + 目录名display_dir(tmp1);break;case 9: back_dir(); //返回上一级目录break;case 10:help();break;case 11:write_file(fp); //将磁盘利用信息写进系统文件,退出return 0;case 12:guolink();break;default:printf("SORRY,没有这个命令\n");break;}}int main(){ int i;printf("操作系统课程设计\n");printf("请输入选择\n");printf("input your choice(1 stand for file control\n 2 stand for guo control)\n");scanf("%d",&i);if(i==1)filecontrol();else if(i==2)guolink();else ;return 0;}六、实验结果显示。