文章目录
- 一、模拟设计MS-DOS操作系统中磁盘文件的存储结构
- 二、模拟便于直接存取的索引文件结构
- 三、具体实现
- 四、实验结果
一、模拟设计MS-DOS操作系统中磁盘文件的存储结构
链接文件可以存放在不连续的物理块中,使用链接字(又称指针)来指出文件中各个物理块之间的关联。在一般情况下,链接文件的第一个物理块号登记在文件目录中,每一块中设置一个链接字,指出链接文件的下一个物理块号,最后一块中的链接字内容为“0”,表示文件结束。如图所示:
采用上述的链接文件结构,只有读出一个物理块信息后才能从链接字中得知下一个物理块号。所以,当用户要在文件中插入一些信息时,文件系统必须多次地请求启动磁盘读出信息才能做插入工作。
MS-DOS操作系统对链接文件结构作了改进,它是把所有的链接指针集中在一起,存放在文件定位表FAT中。查找链接字时不必读出物理块信息可直接从FAT中得到。其设计思想是:假定磁盘上共有N个物理块可供使用,FAT就有N项,初始化时为全“0”,表示对应的物理块均可使用,当要存放文件时,从FAT中寻找为“0”的项,其对应的物理块用来存放文件信息,把文件的链接指针(指出物理块号)登记在FAT中,文件的第一块块号登记在文件目录中。例如:
在MS-DOS中FAT的前两项用来记录盘的类型。第2项起表示盘的分配和链接情况,在上例中第3项为“0表示对应的第3块空闲。图3-2还指出了文件A依次存放在第2,4,20,21,45,46块中,指针为FFF时表示文件结束。
可见,MS-DOS的FAT表起了两个作用:一是起到位示图的作用,可从中判别哪些块被占用,哪些块是空闲的;二是指出了文件的链接情况。
假定磁盘存储空间共有32个物理块,模拟设计文件定位表FAT。文件定位表可以用一个一维数组FAT[031]来定义,其中一个元素与一个物理块对应。当FAT[i]=0时,表示第i块为空闲块;当FAT[i]=FFF时,表示链接文件到第i块结束;当FAT[i]0FAT[i]FFF时,其值指示链接文件中下一个物理块号。
假定磁盘上的每个物理块只能存放一个逻辑记录,设计一个程序把文件的逻辑结构模拟转换成MS-DOS的链接结构。用户要求保存一个已经在主存中的文件时,给出文件名和文件的逻辑记录长度及个数,对一个已经保存的文件,允许用户插入新记录。用键盘输入来模拟用户的要求,输入信息为:
“存” 文件名 逻辑记录长度 逻辑记录个数
“插入” 文件名 逻辑记录号
模拟程序的算法如图:
二、模拟便于直接存取的索引文件结构
索引文件像链接文件一样,文件的逻辑记录信息可存放在非连续的磁盘存储空间中。但这些存放逻辑记录的存储空间不是按链表的形式链接在一起的,而是采用索引表来指出逻辑记录存放的物理位置。
假定把文件中的逻辑记录按次序1,2,3,4,……编号,且约定一个物理块中存放一个逻辑记录。文件中的每一个逻辑记录在索引表中都有一个登记项,登记项指出逻辑记录号以及该记录存放在磁盘上的地址(可用物理块号表示),“最大记录号”表示文件中逻辑记录个数。一个用户建立多个文件时,系统要为每个文件建立一张索引表,索引表的存放地址登记在用户文件目录表中。于是当用户要访问指定文件的某个记录时,系统就能直接查到该记录的物理位置。文件目录与索引表的关系如图:
三、具体实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#define FDF -1
#define FFF -2
#define MAX1 10//宏定义,表示数组的大小。
#define MAX2 32
#define LIST_INIT_SIZE 200 //线性表存储空间的初始容量
#define LISTINCREMENT 20 //线性存储空间的分配增量
typedef struct //结构体定义fab,此结构体包含name,和start两个属性
{
char name;
int start;
}fab;
fab a[MAX1];
typedef struct//索引表
{
int order; //索引表记录号
int block; //物理块号
}indextab;
typedef struct
{
char filename; //文件名
indextab *ind; //索引表指针
int length; //当前长度
int listsize; //当前分配的初始容量
}filetab;
typedef struct//文件目录结构体
{
filetab *file; //文件目录表指针
char name[10]; //用户名
int length; //当前长度
int listsize; //当前分配的初始容量
}usertab;
usertab *newbase;
typedef struct//用户表结构体
{
usertab *user; //用户表指针
int length;
int listsize;
}Sqlist;
Sqlist s;
//以下为全局变量以及各种方法的定义
int fat[MAX2]; //定义fat表项
int filenum = 1; //记录文件的个数,文件数随着保存而增加
int c = 0; //记录所有用户的数量
int h ; //记录每个用户文件的个数
int m ; //m存放的是文件的个数
int count1 = 0; //记录文件的个数,随着转换索引表而动态改变 //count是数量。
char savename[10][1]; //保存用户名
char cr; //记录插入文件的名字
void begin();//定义方法。代码直接操作。
void display();
void insert();
void save();
void change(char name[]);
void after();
void display()//显示方法
{
int i = 0,n,q;
printf("此时fat表纪录情况为:\n");
for(i=0;i<MAX2;i++)
printf("%d : %d\n",i,fat[i]);//此时fat表的初始状态为i=0 fat=0
printf("\n此时文件目录表中的情况为:\n");
printf("-------------------------------------------\n");
printf("文件名\t\t起始块号\t文件长度\n");
for(i=0;i<=filenum;i++)//fulenum是文件个数。初始状态为1
{
q=0;
n=a[i].start;//第一个结构体
while(1)
{
n = fat[n];
q++; //记录此文件的逻辑记录长度
if(n==FFF)
break;
}
printf("%4c\t\t%4d\t\t%4d\n",a[i].name,a[i].start,q);
}
printf("-------------------------------------------\n");
}
void begin()
{
int i,j = 0;
printf("初始化fat表\n");
fat[0] = FDF;//宏定义FDF=-1
fat[1] = FFF;//宏定义FFF=-2
for(i=2;i<MAX2;i++)
fat[i] = 0;
a[0].name = 'A';
a[0].start = 2;
fat[a[0].start] = 5; //初始化第一个文件
fat[5] = 8;
fat[8] = 11;
fat[11] = 18;
fat[18] = 24;
fat[24] = FFF;
a[1].name = 'B'; //初始化第二个文件
a[1].start = 6;
fat[a[1].start] = 9;
fat[9] = 14;
fat[14] = 19;
fat[19] = 22;
fat[22] = 28;
fat[28] = 30;
fat[30] = FFF;
display();
s.user = (usertab *)malloc(LIST_INIT_SIZE*sizeof(usertab)); //为用户分配空间
if(!s.user)
exit(-2);
s.length = 0;
s.listsize = LIST_INIT_SIZE;
}
void insert()
{
int k,j,start1,s,n,q,w;
int i=0,p=0;
char iname,jname;
printf("请输入你要插入的文件名\n");
fflush(stdin);//重写操作
scanf("%c",&iname);
for(i=0;i<MAX1;i++) //在文件目录表中找到此文件
{
if(a[i].name!=iname)
{
q = i; //记录是第几个文件
continue;
}
else
{
jname = a[i].name;
cr = iname; //记录插入文件的名字
printf("存在此文件!\n");
n = a[i].start;//初始化文件
while(1)
{
n = fat[n];
p++; //记录此文件的逻辑记录长度
if(n==FFF)
break;
}
printf("此文件的记录长度为:%d\n",p);
while(1)
{
printf("请在此1--%d范围内输入你要插入的记录号\n",p);
scanf("%d",&k);
fflush(stdin);
if(k<=0||k>p)
{
printf("记录号错误重新输入\n");
continue;
}
else break;
}
for(i=0;i<MAX2;i++) //查找第一个空闲块号
{
if(fat[i]!=0)
{
w = i;
continue;
}
else
{
printf("有空闲块%d\n",i);
j = i; //j为空闲块号
printf("逻辑纪录号对应的物理块号为:");
for(i=0;i<MAX1;i++) //查找此文件第一个物理块号
{
if(iname==a[i].name)
{
start1=a[i].start;
break;
}
}
for(i=0;i<k-1;i++) //查找逻辑块号对应的物理块号
{
m = fat[start1];
start1 = m;
}
printf("%d\n",start1);
s = fat[start1]; //插入纪录
fat[start1] = j;
fat[j] = s;
break;
}
if(w==MAX2-1&&fat[w]!=0)
{
printf("无空闲块结束\n");
break;
}
}
}
break;
}
if(q==MAX1-1&&jname!=iname)
printf("不存在此文件,结束\n");
}
void save()
{
char name1;
int num1,i,count=0;
int b[MAX2]; //数组b中存放空闲区物理块号
printf("请输入要保存文件的信息:文件名和长度\n");
fflush(stdin);
scanf("%c %d",&name1,&num1);
fflush(stdin);
filenum++;
m=filenum; //m存放的是文件的个数
for(i=0;i<MAX1;i++)
{
if(name1==a[i].name)
{
printf("有同名文件!\n");
return;
}
}
printf("无同名文件,可以保存!\n");
for(i=0;i<MAX2;i++)
{
if(fat[i]==0)
{
b[count] = i;
count++;
}
}
if(count<num1)
{
printf("磁盘空间不够!\n");
return;
}
a[filenum].name = name1;
a[filenum].start = b[0];
printf("已将文件存入物理块中\n");
for(i=0;i<num1-1;i++)
fat[b[i]] = b[i+1];
fat[b[i]] = FFF;
}
void change(char name[])
{
int j=0; //记录当前用户文件的个数
int k,n,i;
int flag;
char fname;
if(s.length>=s.listsize)//listsize为分配的初始容量
{
newbase = (usertab *)realloc(s.user,(s.listsize+LISTINCREMENT)*sizeof//为用户分配储存空间,realloc隶属于malloc头文件
(usertab));
if(!newbase)
exit(-2);
s.user = newbase;
s.length+=LISTINCREMENT;//线性储存空间分配增量
}
for(i=0;i<10;i++) //将用户名记录到用户表中
s.user[c].name[i] = name[i];
printf("用户的名字:%s\n",s.user[c].name);
s.user[c].file = (filetab *)malloc(LIST_INIT_SIZE*sizeof(filetab)); //为文件目录表分配空间
if(!s.user[c].file)
exit(-2);
s.user[c].length = 0;
s.length++; //用户个数加一
s.user[c].listsize = LIST_INIT_SIZE;
while(1)
{
if(s.user[c].length>=s.user[c].listsize) //分配空间
{
newbase->file = (filetab *)realloc(s.user[c].file,(s.user
[c].listsize+LISTINCREMENT)*sizeof(filetab));
if(!newbase->file)
exit(-2);
s.user[c].file = newbase->file;
s.user[c].length+=LISTINCREMENT;//线性储存空间分配增量
}
repeat:
fflush(stdin);
printf("请输入此用户的文件名\n");
fflush(stdin);
scanf("%c",&fname);
fflush(stdin);
for(i=0;i<=m;i++) //查找此文件是否被其他用户占有
{
if(fname==savename[i][1])
{
printf("此文件已经被别的用户占用请重新输入\n");
goto repeat;
}
}
for(i=0;i<MAX1;i++)
{
if(fname==a[i].name)
{
h=i; //h记录用户的文件
break;
}
else if(i==MAX1-1)
{
printf("不存在此文件重新输入\n");
goto repeat;
}
}
savename[h][1] = fname;
count1++; //索引表中文件加一
s.user[c].file[j].filename = fname;
s.user[c].file[j].ind = (indextab *)malloc(LIST_INIT_SIZE*sizeof(indextab)); //为文件索引表分配空间
if (!s.user[c].file[j].ind)
exit(-2);
s.user[c].file[j].length=0;
s.user[c].length++; //用户文件长度加一
s.user[c].file[j].listsize = LIST_INIT_SIZE;
n = a[h].start;
for(k=0;;k++)
{
if(s.user[c].file[j].length>=s.user[c].file[j].listsize)
{
newbase->file[j].ind = (indextab *)realloc(s.user[c].file[j].ind,(s.user[c].file[j].listsize+LISTINCREMENT)*sizeof(indextab));
if(!newbase->file[j].ind)
exit(-2);
s.user[c].file[j].ind = newbase->file[j].ind;
s.user[c].file[j].length+=LISTINCREMENT;
}
s.user[c].file[j].ind[k].order = k+1;//索引表记录号
s.user[c].file[j].ind[k].block = n;//物理模块号
n = fat[n];
s.user[c].file[j].length++;
if(n==-2) //FFF=-2
break;
}
j++;
c++;//
if(count1-1==filenum)
{
printf("fat表转换完毕!\n");
return;
}
while(1)
{
printf("此用户是否还有另外的文件?如果有文件输入1,否则输入0\n");
fflush(stdin);
scanf("%d",&flag);
fflush(stdin);
if(flag==1)
{
c--;
break;
}
else if(flag!=0)
{
printf("输入错误,重新输入\n");
continue;
}
else
break;
}
if(flag==0)
break;
}
}
void after()
{
int i,j,k;
printf("**********************************\n");
fflush(stdin);
for(k=0;k<c;k++)
{
fflush(stdin);//重写操作。目的是清除缓存。
printf("用户%s的索引表为:\n",s.user[k].name);
fflush(stdin);
for(i=0;i<s.user[k].length;i++)
{
printf("文件名:%c\n",s.user[k].file[i].filename);
printf("记录号:\t物理块号:\n");
for(j=0;j<s.user[k].file[i].length;j++)
printf("%4d\t%4d\n",s.user[k].file[i].ind[j].order,s.user
[k].file[i].ind[j].block);
}
}
}
int main()
{
char name[10];
int x,i;
while(1)
{
for(i=0;i<10;i++)
savename[i][1] ='\0';
printf("***************************************************************\n");
printf("\n\t模拟设计MS-DOS操作系统中磁盘文件的索引文件结构\n");
printf("\n\t\t选择1: 初始化fat");
printf("\n\t\t选择2: 显示fat表");
printf("\n\t\t选择3: 插入逻辑记录号操作");
printf("\n\t\t选择4: 保存文件操作");
printf("\n\t\t选择5: 转换索引表");
printf("\n\t\t选择6: 显示转换后的索引表");
printf("\n\t\t选择0: 结束");
printf
("\n\n***************************************************************\n");
printf("请输入选择的操作:");
scanf("%d",&x);
switch(x)
{
case 1:begin();
break;
case 2:display();
break;
case 3:insert();
break;
case 4:save();
break;
case 5:printf("\n*********************************************\n");
while(count1-1<filenum) //在存入索引表的文件小于等于总文件个数的时候
{
printf("将fat表转换成索引表\n");
while(1)
{
printf("请输入用户名\n");
fflush(stdin);
scanf("%s",name);
change(name);
break;
}
}
break;
case 6:after();
break;
case 0:break;
}
if(x==0) break;
}
return 0;
}
四、实验结果