文章目录

  • 一、模拟设计MS-DOS操作系统中磁盘文件的存储结构
  • 二、模拟便于直接存取的索引文件结构
  • 三、具体实现
  • 四、实验结果


一、模拟设计MS-DOS操作系统中磁盘文件的存储结构

  链接文件可以存放在不连续的物理块中,使用链接字(又称指针)来指出文件中各个物理块之间的关联。在一般情况下,链接文件的第一个物理块号登记在文件目录中,每一块中设置一个链接字,指出链接文件的下一个物理块号,最后一块中的链接字内容为“0”,表示文件结束。如图所示:

windows 磁盘索引_操作系统

  采用上述的链接文件结构,只有读出一个物理块信息后才能从链接字中得知下一个物理块号。所以,当用户要在文件中插入一些信息时,文件系统必须多次地请求启动磁盘读出信息才能做插入工作。

  MS-DOS操作系统对链接文件结构作了改进,它是把所有的链接指针集中在一起,存放在文件定位表FAT中。查找链接字时不必读出物理块信息可直接从FAT中得到。其设计思想是:假定磁盘上共有N个物理块可供使用,FAT就有N项,初始化时为全“0”,表示对应的物理块均可使用,当要存放文件时,从FAT中寻找为“0”的项,其对应的物理块用来存放文件信息,把文件的链接指针(指出物理块号)登记在FAT中,文件的第一块块号登记在文件目录中。例如:

windows 磁盘索引_c语言_02

  在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]0FAT[i]FFF时,其值指示链接文件中下一个物理块号。

  假定磁盘上的每个物理块只能存放一个逻辑记录,设计一个程序把文件的逻辑结构模拟转换成MS-DOS的链接结构。用户要求保存一个已经在主存中的文件时,给出文件名和文件的逻辑记录长度及个数,对一个已经保存的文件,允许用户插入新记录。用键盘输入来模拟用户的要求,输入信息为:

  “存” 文件名 逻辑记录长度 逻辑记录个数

  “插入” 文件名 逻辑记录号

  模拟程序的算法如图:

windows 磁盘索引_windows 磁盘索引_03

二、模拟便于直接存取的索引文件结构

  索引文件像链接文件一样,文件的逻辑记录信息可存放在非连续的磁盘存储空间中。但这些存放逻辑记录的存储空间不是按链表的形式链接在一起的,而是采用索引表来指出逻辑记录存放的物理位置。

  假定把文件中的逻辑记录按次序1,2,3,4,……编号,且约定一个物理块中存放一个逻辑记录。文件中的每一个逻辑记录在索引表中都有一个登记项,登记项指出逻辑记录号以及该记录存放在磁盘上的地址(可用物理块号表示),“最大记录号”表示文件中逻辑记录个数。一个用户建立多个文件时,系统要为每个文件建立一张索引表,索引表的存放地址登记在用户文件目录表中。于是当用户要访问指定文件的某个记录时,系统就能直接查到该记录的物理位置。文件目录与索引表的关系如图:

windows 磁盘索引_c语言_04

三、具体实现

#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;
}

四、实验结果

windows 磁盘索引_操作系统_05


windows 磁盘索引_操作系统_06


windows 磁盘索引_c语言_07


windows 磁盘索引_windows 磁盘索引_08


windows 磁盘索引_windows 磁盘索引_09


windows 磁盘索引_操作系统_10


windows 磁盘索引_操作系统_11


windows 磁盘索引_数据结构_12


windows 磁盘索引_数据结构_13


windows 磁盘索引_数据结构_14


windows 磁盘索引_算法_15


windows 磁盘索引_算法_16