文件系统简单模拟

  • Post author:
  • Post category:其他




文件系统



一、实验简介

在模拟的I/O系统之上开发一个简单的文件系统。用户通过create, open, read等命令与文件系统交互。文件系统把磁盘视为顺序编号的逻辑块序列,逻辑块的编号为0至L − 1。I/O系统利用内存中的数组模拟磁盘。



二、实验内容



设计一个文件系统

(1)用磁盘中的一个文件(大小事先指定,512KB)来模拟一个磁盘

(2)设计一个I/O系统,用来实现磁盘文件与模拟磁盘之间的数据存储

(3)设计一个文件系统,用来实现模拟磁盘与用户之间的人机交互



三、程序设计



3.1.I/O系统

实际物理磁盘的结构是多维的:有柱面、磁头、扇区等概念。I/O系统的任务是隐藏磁盘的结构细节,把磁盘以逻辑块的面目呈现给文件系统。逻辑块顺序编号,编号取值范围为0至L−1,其中L表示磁盘的存储块总数。

本次实验中,我利用数组ldisk[C][H][B]构建磁盘模型,其中CHB 分别表示柱面号,磁头号和扇区号。每个扇区大小为512字节。

I/O系统实现的功能是:


(1)从文件系统接收命令,根据命令指定的逻辑块号把磁盘块的内容读入命令指定的内存区域;(把逻辑块x的内容读入到指针p指向的内存位置,拷贝的字符个数为strlen)

int read_block(int x, char *p, int strlen)
{
    int i,j,k;
    i=x/(H*B);
    j=(x-i*H*B)/B;
    k=(x-i*H*B-j*B);
    strncpy(p, &ldisk[i][j][k], strlen);
    return 0;
}


(2)从文件系统接收命令,把命令指定的内存区域内容写入磁盘块;(把指针p指向的内容写入逻辑块x,拷贝的字符个数为strlen)

int write_block(int x, char *p, int strlen)
{
    int i,j,k;
    i=x/(H*B);
    j=(x-i*H*B)/B;
    k=(x-i*H*B-j*B);
    strncpy(&ldisk[i][j][k], p, strlen);
    return 0;
}


(3)用来把数组ldisk 存储到文件;

int FileToArray()
{
    int i,j,k;
    fseek(Disk,0,SEEK_SET);
    for(i=0; i<C; i++)
    {
        for(j=0; j<H; j++)
        {
            for(k=0; k<B; k++)
            {
                if(fread(&ldisk[i][j][k],512,1,Disk)!=1)
                {
                    printf("文件内容恢复到数组失败!\n");
                    k=B;
                    j=H;
                    i=C;//退出
                }
            }
        }
    }
    return 1;
}


(4)用来把文件内容恢复到数组ldisk;

int ArrayToFile()
{
    int i,j,k;
    fseek(Disk,0,SEEK_SET);
    for(i=0; i<C; i++)
    {
        for(j=0; j<H; j++)
        {
            for(k=0; k<B; k++)
            {
                if(fwrite(&ldisk[i][j][k],512,1,Disk)!=1)
                {
                    printf("数组存储到文件失败!\n");
                    k=B;
                    j=H;
                    i=C;//退出
                }
            }
        }
    }
    return 1;
}


I/O系统代码整体架构:


在这里插入图片描述



3.2.文件系统(位于I/O系统之上)

自定义:

#define BlkNum 512 //磁盘块的数目(编号从0开始)

#define BlkSize 1024 //磁盘块大小为1K



3.2.1 文件系统的组织

磁盘的前4个块是保留区(超级块),其中包含如下信息:

位图和文件描述符。位图用来描述磁盘块的分配情况。位图中的每一位对应一个逻辑块。创建或者删除文件,以及文件的长度发生变化时,文件系统都需要进行位图操作。

前5个块的剩余部分包含一组文件描述符。每个文件描述符包含如下信息:

(1)文件长度,单位字节

(2)文件分配到的磁盘块号数组。该数组的长度是系统参数。(我设置为4)


定义结构体:

typedef struct
{
    char  blk_map[BlkNum];//磁盘块位图
    char  inode_map[InodeNum];//文件描述符位图
    char  blk_used[4];//已被使用的磁盘块数目
    char  inode_used[4];//已被使用的文件描述符数目
} SuperBlk;//超级块(保留区)
typedef struct
{
    char  blk_identifier[BlkPerNode][4];//占用的磁盘块编号
    char  blk_num[4];//占用的磁盘块数目
    char  file_size[4];//文件的大小
} Inode;//文件描述符


自定义常量:

#define InodeNum	    112//文件描述符数目
#define BlkPerNode	    4//每个文件包含的最大的磁盘块数目
#define K	            4//超级块占磁盘块数目(0\1\2\3)
#define SuperBlkBeg	    0//超级块起始磁盘块(0)
#define InodeBeg	    1//文件描述符起始磁盘块(1\2\3)


自定义变量:

SuperBlk	super_blk;//文件系统的超级块
Inode 	record_inode[InodeNum];//文件描述符使用情况


功能函数:

void show_blk_map()//显示磁盘块使用情况,0代表未被使用,1代表已使用
{
    int i=0;
    for(i=0; i<BlkNum; i++)
    {
        printf("%c   ",super_blk.blk_map[i]);
        if((i+1)%24==0)
            printf("\n");
    }
    printf("\n\t已被使用的磁盘块数目为:%d\n",char4TOint(super_blk.blk_used));
}
void show_inode_map()//显示文件描述符使用情况,0代表未被使用,1代表已使用
{
    int i=0;
    for(i=0; i<InodeNum; i++)
    {
        printf("%c   ",super_blk.inode_map[i]);
        if((i+1)%24==0)
            printf("\n");
    }
    printf("\n\t已被使用的文件描述符数目为:%d\n",char4TOint(super_blk.inode_used));
}



3.2.2目录

文件系统中仅设置一个目录,该目录包含文件系统中的所有文件。除了不需要显示地创建和删除之外,目录在很多方面和普通文件相像。目录对应0号文件描述符。初始状态下,目录中没有文件,所有,目录对应的描述符中记录的长度应为0,而且也没有分配磁盘块。每创建一个文件,目录文件的长度便增加一。目录文件的内容由一系列的目录项组成,其中每个目录项由如下内容组成:

(1)文件名 (2)文件描述符序号


定义结构体:

typedef struct
{
    char  name[20];//文件名
    char  inode_num[4];//文件描述符序号
} Dir;//目录


自定义常量:

#define MaxDirNum	112//目录所支持的最大的文件数


自定义变量:

Dir 	dir_table[MaxDirNum];//目录使用情况


功能函数:

int directory()//显示所有文件及其长度,以及占用磁盘号
{
    int i=0,j=0,k=0,x=0;
    if(char4TOint(super_blk.inode_used)==1)
    {
        printf("    文件系统未含有文件!\n");
    }
    else
    {
        for(i=1; i<InodeNum; i++)
        {
            if(super_blk.inode_map[i]=='1')
            {
                for(j=0; j<MaxDirNum; j++)
                {
                    if(char4TOint(dir_table[j].inode_num)==i)
                        break;
                }
                printf("    文件名为:");
                for(x=0; x<20; x++)
                {
                    if(dir_table[j].name[x]!='!')
                        printf("%c",dir_table[j].name[x]);
                }
                printf("     文件大小为:%d字节\n",char4TOint(record_inode[i].file_size));
                if(char4TOint(record_inode[i].blk_num)==0)
                {
                    printf("    文件未占用磁盘块!");
                }
                else
                {
                    printf("    文件占用的磁盘块编号为: ");
                    for(k=0; k<char4TOint(record_inode[i].blk_num); k++)
                        printf("%d ",char4TOint(record_inode[i].blk_identifier[k]));
                }
                printf("\n\n");
            }
        }
    }
    return 0;
}



3.2.3 文件的创建与删除

创建文件时需要进行如下操作:

(1)检查目录中是否已含有文件名相同文件存在

(2)检查文件系统存储文件是否已达上限

(3)找一个空闲文件描述符(扫描record_inode[1]~record_inode[InodeNum])

(4)在文件目录里为新创建的文件分配一个目录项

(5)在分配到的目录项里记录文件名及描述符编号

(6)返回状态信息(如有无错误发生等)


创建文件函数:

int create(char *filename)//根据指定的文件名创建新文件
{
    int i;
    //printf("%d\n",strlen(filename));
    if(strlen(filename)>=20)
    {
        printf("    文件名过长!\n");
        return -1;
    }
    for(i=0; i<MaxDirNum; i++)
    {
        if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
        {
            printf("    文件系统中已存在该文件,请更换文件名或将已存在文件删除!\n");
            return -1;
        }
    }
    if(char4TOint(super_blk.inode_used)>=InodeNum)
    {
        printf("    文件系统中存储文件已达上限,请先删除一些不必要的文件后再创建新文件!\n");
        return -1;
    }
    strncpy(dir_table[char4TOint(super_blk.inode_used)].name,filename,strlen(filename));
    for(i=1; i<InodeNum; i++)
    {
        if(super_blk.inode_map[i]=='0')
        {
            intTOchar4(i,dir_table[char4TOint(super_blk.inode_used)].inode_num);
            intTOchar4(0,record_inode[i].blk_num);
            intTOchar4(0,record_inode[i].file_size);
            super_blk.inode_map[i]='1';
            break;
        }
    }
    i=char4TOint(super_blk.inode_used)+1;
    intTOchar4(i,super_blk.inode_used);
    printf("    文件%s创建成功!\n",filename);
    return 0;
}

删除文件时需要进行如下操作(假设文件没有被打开):

(1)在目录里搜索该文件的描述符编号

(2)删除该文件对应的目录项并更新位图

(3)释放文件描述符

(4)返回状态信息

注:当文件没已打开时,只有先关闭文件,才可进行删除


删除文件函数:

int destroy(char *filename)//删除指定文件
{
    int i,j,k;
    char use[512];
    for(i=0; i<OpenFileNum; i++)
    {
        if(strcmp(OpenFile_table[i].name, filename)==0)
        {
            printf("    %s文件已打开,请先关闭文件后再进行删除。\n",filename);
            return -1;
        }
    }
    for(i=1; i<MaxDirNum; i++)
    {
        if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
        {
            strncpy(dir_table[i].name, "!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
            intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].file_size);
            if(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num)!=0)
            {
                memset(&use, ' ', 512);
                //printf("%d\n",char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0]));
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2+1,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2+1,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2+1,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2+1,use,512);
                k = char4TOint(super_blk.blk_used)-4;
                intTOchar4(k,super_blk.blk_used);
            }
            for(j=0; j<char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num); j++)
            {
                super_blk.blk_map[char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j])]='0';
                intTOchar4(BlkNum,record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j]);
            }
            intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].blk_num);
            super_blk.inode_map[char4TOint(dir_table[i].inode_num)]='0';
            intTOchar4(InodeNum,dir_table[i].inode_num);
            i=char4TOint(super_blk.inode_used)-1;
            intTOchar4(i,super_blk.inode_used);

            printf("    %s文件已删除!\n",filename);
            break;
        }
    }
    if(i==MaxDirNum)
    {
        printf("    没有在目录中找到该文件,请确保输入的文件名正确!\n");
    }
    return 0;
}



3.2.4 文件的打开与关闭

文件系统维护一张打开文件表。打开文件表的长度固定,其表目含如下信息:

(1)读写指针 (2)文件名 (3)文件描述符

文件被打开时,便在打开文件表中为其分配一个表目;文件被关闭时,其对应的表目被释放。


定义结构体:

typedef struct
{
    int  pointer1;//读写指针(选择盘块)
    int  pointer2;//读写指针(盘块内偏移)
    char  name[30];//文件名
    int  inode_num;//文件描述符序号
} OpenFile;//已打开文件


自定义常量:

#define OpenFileMaximumNum   10//文件系统同时打开文件最大数目


自定义变量:

OpenFile    OpenFile_table[OpenFileMaximumNum];//已打开文件
int OpenFileNum=0;//已打开文件数目

打开文件时需要进行的操作如下:

(1)搜索目录找到文件对应的描述符编号

(2)在打开文件表中分配一个表目

(3)在分配到的表目中把读写指针置为0,并记录描述符编号

(4)返回文件对应的描述符编号


打开文件函数:

int open_file(char *filename)//打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作
{
    int i;
    if(OpenFileNum>OpenFileMaximumNum)
    {
        printf("    此时已打开文件数目达到文件系统最大要求,如要继续打开此文件,请先关闭一些不再使用的文件!\n");
        return -1;
    }
    for(i=0; i<MaxDirNum; i++)
    {
        if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
        {
            strcpy(OpenFile_table[OpenFileNum].name, filename);
            OpenFile_table[OpenFileNum].inode_num = char4TOint(dir_table[i].inode_num);
            OpenFileNum++;
            printf("    %s文件已打开,文件索引号为%d。\n",filename,char4TOint(dir_table[i].inode_num));
            break;
        }
    }
    if(i==MaxDirNum)
    {
        printf("    没有在目录中找到该文件,请确保输入的文件名正确!\n");
    }
    return char4TOint(dir_table[i].inode_num);
}

关闭文件时需要进行的操作如下:

(1)释放该文件在打开文件表中对应的表目

(2)返回状态信息


关闭文件函数

int close_file(int index)//关闭指定文件
{
    int i=0,j=0,judge=0;
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            printf("    %s文件已关闭。\n",OpenFile_table[i].name);
            for(j=i; j<OpenFileNum-1; j++)
            {
                OpenFile_table[j].inode_num = OpenFile_table[j+1].inode_num;
                strcpy(OpenFile_table[j].name, OpenFile_table[j+1].name);
                OpenFile_table[j].pointer1 = OpenFile_table[j+1].pointer1;
                OpenFile_table[j].pointer2 = OpenFile_table[j+1].pointer2;
            }
            OpenFile_table[j].inode_num = InodeNum;
            strcpy(OpenFile_table[j].name, "\0");
            OpenFile_table[j].pointer1 = 0;
            OpenFile_table[j].pointer2 = 0;
            OpenFileNum--;
            judge = 1;
            break;
        }
    }
    if(judge==0)
    {
        printf("    没有在已打开文件中找到该文件,请确保输入的索引号正确!\n");
    }
    return 0;
}



3.2.5 文件读写

文件打开之后才能进行读写操作.读操作需要完成的任务如下:

(1)计算读写指针对应的位置在读写缓冲区中的偏移

(2)把从模拟磁盘中读入数据(或向模拟磁盘中写入缓冲区数据),直到发生下列事件之一:到达文件尾或者已经拷贝了指定的字节数。


指针偏移函数:

/*把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,
它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置*/
int lseek_file(int index, int pos)
{
    int i=0;
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            if(char4TOint(record_inode[index].file_size) == 0)
            {
                printf("    该文件尚未存储任何内容,不允许偏移读写指针!\n");
            }
            else
            {
                if(char4TOint(record_inode[index].file_size) < pos)
                {
                    printf("    该文件允许偏移读写指针最大为%d,指针偏移失败 !\n",char4TOint(record_inode[index].file_size));
                }
                else
                {
                    OpenFile_table[i].pointer1 = pos/1024;
                    OpenFile_table[i].pointer2 = pos%1024;
                }
            }
            break;
        }
    }
    if(i==OpenFileNum)
    {
        printf("    索引号所对应的文件没有被打开,请先打开该文件!\n");
    }
    return 0;
}


读取文件函数:

int read_file(int index, int number)//从指定文件顺序读入number个字节到读写缓冲区buffer。读操作从文件的读写指针指示的位置开始
{
    int i=0,j=0,x=0,y=0;
    char use[8][512];
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            if(char4TOint(record_inode[index].file_size) == 0)
            {
                printf("    该文件为空!\n");
            }
            else
            {
                read_block(char4TOint(record_inode[index].blk_identifier[0])*2,  use[0],512);
                read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
                read_block(char4TOint(record_inode[index].blk_identifier[1])*2,  use[2],512);
                read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
                read_block(char4TOint(record_inode[index].blk_identifier[2])*2,  use[4],512);
                read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
                read_block(char4TOint(record_inode[index].blk_identifier[3])*2,  use[6],512);
                read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
                x = OpenFile_table[i].pointer1*2;
                if(OpenFile_table[i].pointer2>512)
                {
                    x++;
                    y = OpenFile_table[i].pointer2 - 512;
                }
                else
                {
                    y = OpenFile_table[i].pointer2;
                }
                if((char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
                {
                    for(j=0; j<=(char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
                    {
                        buffer[j] = use[x][y];
                        y++;
                        if(y==512)
                        {
                            x++;
                            y=0;
                        }
                    }
                    printf("    文件内容已读入到末尾,共读取%d个字节!\n",j);
                    buffer[j++]='\0';
                }
                else
                {
                    for(j=0; j<=number; j++)
                    {
                        buffer[j] = use[x][y];
                        y++;
                        if(y==512)
                        {
                            x++;
                            y=0;
                        }
                    }
                    buffer[j++]='\0';
                }
                printf("    文件内容已读入到读写缓冲区buffer中!内容为:\n\t\t%s\n",&buffer);
                lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
            }
            break;
        }
    }
    if(i==OpenFileNum)
    {
        printf("    索引号所对应的文件没有被打开,请先打开该文件!\n");
    }
    return 0;
}


写入文件函数:

int write_file(int index, int number)//把读写缓冲区buffer的number个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始
{
    int i=0,j=0,k=0,x=0,y=0,z=0,w;
    char use[8][512];
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            printf("    请输入你想写入该文件的内容:\n\t");
            for(j=0; j<=number; j++)
            {
                scanf("%c",&buffer[j]);
            }
            if(char4TOint(record_inode[index].blk_num)==0)
            {
                intTOchar4(4,record_inode[index].blk_num);
                for(z=0; z<4; z++)
                {
                    for(k=0; k<BlkNum; k++)
                    {
                        if(super_blk.blk_map[k]=='0')
                        {
                            intTOchar4(k,record_inode[index].blk_identifier[z]);
                            super_blk.blk_map[k]='1';
                            break;
                        }
                    }
                }
                w=char4TOint(super_blk.blk_used)+4;
                intTOchar4(w,super_blk.blk_used);
            }
            read_block(char4TOint(record_inode[index].blk_identifier[0])*2,  use[0],512);
            read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
            read_block(char4TOint(record_inode[index].blk_identifier[1])*2,  use[2],512);
            read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
            read_block(char4TOint(record_inode[index].blk_identifier[2])*2,  use[4],512);
            read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
            read_block(char4TOint(record_inode[index].blk_identifier[3])*2,  use[6],512);
            read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
            x = OpenFile_table[i].pointer1*2;
            if(OpenFile_table[i].pointer2>512)
            {
                x++;
                y = OpenFile_table[i].pointer2 - 512;
            }
            else
            {
                y = OpenFile_table[i].pointer2;
            }
            if((4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
            {
                for(j=0; j<=(4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
                {
                    use[x][y] = buffer[j];
                    y++;
                    if(y==512)
                    {
                        x++;
                        y=0;
                    }
                }
                printf("    文件内容未全部写入指定文件中,文件内容已达到最大值,写入%d个字节!\n",j);
            }
            else
            {
                for(j=0; j<=number; j++)
                {
                    use[x][y] = buffer[j];
                    y++;
                    if(y==512)
                    {
                        x++;
                        y=0;
                    }
                    //printf("%c",use[x][y]);
                }
                printf("    文件内容已全部写入指定文件中!\n");
            }
            //printf("%d\n",j);
            w = char4TOint(record_inode[index].file_size)+j;
            intTOchar4(w,record_inode[index].file_size);
            write_block(char4TOint(record_inode[index].blk_identifier[0])*2,  use[0],512);
            write_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
            write_block(char4TOint(record_inode[index].blk_identifier[1])*2,  use[2],512);
            write_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
            write_block(char4TOint(record_inode[index].blk_identifier[2])*2,  use[4],512);
            write_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
            write_block(char4TOint(record_inode[index].blk_identifier[3])*2,  use[6],512);
            write_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
            lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
        }
        break;
    }
    if(i==OpenFileNum)
    {
        printf("    索引号所对应的文件没有被打开,请先打开该文件!\n");
    }
    return 0;
}



3.3.用户接口设计

简单清晰的操作方式是用户喜欢一个程序或软件的必要条件,特此编写以下函数,使程序操作起来更加方便快捷。


用户指令设计及路径:

/*指令集合*/
char* command[]= {"format","quit","directory","create","destroy","open","close","lseek","read","write","help","sbm","sim","sOF"};
/*路径名*/
char path[20]="file_system(yss)$ ";//文件系统(yss 袁少随)


辅助功能函数:

int format_fs()//格式化文件系统
{
    init_Dick();初始化磁盘数组
    char use[512];
    int i=0;
    memset(&super_blk.blk_map, '0', BlkNum);//初始化超级块
    memset(&super_blk.inode_map, '0', InodeNum);
    super_blk.blk_map[0]='1';
    super_blk.blk_map[1]='1';
    super_blk.blk_map[2]='1';
    super_blk.blk_map[3]='1';
    super_blk.blk_map[4]='1';
    super_blk.blk_map[5]='1';
    super_blk.blk_map[6]='1';
    super_blk.blk_map[7]='1';
    intTOchar4(8,super_blk.blk_used);
    super_blk.inode_map[0]='1';
    intTOchar4(1,super_blk.inode_used);
    for(i=0; i<InodeNum; i++)//初始化文件描述符使用情况
    {
        intTOchar4(BlkNum,record_inode[i].blk_identifier[0]);
        intTOchar4(BlkNum,record_inode[i].blk_identifier[1]);
        intTOchar4(BlkNum,record_inode[i].blk_identifier[2]);
        intTOchar4(BlkNum,record_inode[i].blk_identifier[3]);
        intTOchar4(0,record_inode[i].blk_num);
        intTOchar4(0,record_inode[i].file_size);
    }
    strncpy(dir_table[0].name,"yss_contents########",sizeof("yss_contents########")-1);//创建目录文件
    intTOchar4(0,dir_table[0].inode_num);
    intTOchar4(0,record_inode[0].blk_num);
    intTOchar4(0,record_inode[0].file_size);
    super_blk.inode_map[0]='1';
    for(i=1; i<MaxDirNum; i++)//初始化目录使用情况
    {
        intTOchar4(InodeNum,dir_table[i].inode_num);
        strncpy(dir_table[i].name,"!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
    }
    write_block(0,&super_blk,632);
    write_block(2,&record_inode,2688);
    write_block(8,&dir_table,2688);
    memset(&use, ' ', 512);
    for(i=16; i<L; i++)
    {
        write_block(i,use,512);
    }
    //printf("%d\n",sizeof(super_blk));
    //printf("%d\n",sizeof(record_inode));
    //printf("%d\n",sizeof(dir_table));
    ArrayToFile();
    printf("    格式化文件系统成功!\n");
    return 0;
}

void help()//求助函数
{
    printf("***********************************************************************************\n");
    printf("* 下面是本文件系统所支持的命令:                                                  *\n");
    printf("*           格式化文件系统:     format                                           *\n");
    printf("*           退出文件系统:       quit                                             *\n");
    printf("*           显示目录内容:       directory                                        *\n");
    printf("*           创建文件:           create                                           *\n");
    printf("*           删除文件:           destroy                                          *\n");
    printf("*           打开文件:           open                                             *\n");
    printf("*           关闭文件:           close                                            *\n");
    printf("*           文件指针偏移:       lseek                                            *\n");
    printf("*           读文件:             read                                             *\n");
    printf("*           写文件:             write                                            *\n");
    printf("*           请求帮助:           help                                             *\n");
    printf("*           磁盘块使用情况:     sbm                                              *\n");
    printf("*           文件描述符使用情况: sim                                              *\n");
    printf("*           已打开文件列表:     sOF                                              *\n");
    printf("***********************************************************************************\n");
}


主函数:


在这里插入图片描述

int main()
{
    printf("***********************************************************************************\n");
    printf("* 欢迎来到yss的文件系统!!!                                                     *\n");
    printf("* 介绍:此文件系统是模拟Linux系统所制作,在这里你将体验到命令行的乐趣!           *\n");
    printf("*           格式化文件系统:     format                                           *\n");
    printf("*           退出文件系统:       quit                                             *\n");
    printf("*           显示目录内容:       directory                                        *\n");
    printf("*           创建文件:           create                                           *\n");
    printf("*           删除文件:           destroy                                          *\n");
    printf("*           打开文件:           open                                             *\n");
    printf("*           关闭文件:           close                                            *\n");
    printf("*           文件指针偏移:       lseek                                            *\n");
    printf("*           读文件:             read                                             *\n");
    printf("*           写文件:             write                                            *\n");
    printf("*           请求帮助:           help                                             *\n");
    printf("*           磁盘块使用情况:     sbm                                              *\n");
    printf("*           文件描述符使用情况: sim                                              *\n");
    printf("*           已打开文件列表:     sOF                                              *\n");
    printf("* 好了!现在请开始你的表演!!!                                                  *\n");
    printf("***********************************************************************************\n");
    char comm[30],filename[20];
    int i,quit=0,choice,index,number;
    Disk = fopen(DISK,"r+");//打开磁盘文件
    if(Disk == NULL)
    {
        printf("打开磁盘文件失败,请查看是否已创建disk.txt!\n");
    }
    init_fs();//初始化文件系统
    while(1)
    {
        printf("%s ",path);
        scanf("%s",comm);
        choice=-1;
        for(i=0; i<CommanNum; ++i)
        {
            if(strcmp(comm,command[i])==0)
            {
                choice=i;
                break;
            }
        }
        switch(choice)
        {
        /*格式化文件系统*/
        case 0:
            format_fs();
            printf("\n");
            break;
        /*退出文件系统*/
        case 1:
            quit=1;
            break;
        /*显示目录内容*/
        case 2:
            directory();
            printf("\n");
            break;
        /*创建文件*/
        case 3:
            printf("\t请输入文件名:");
            scanf("%s",filename);
            create(filename);
            printf("\n");
            break;
        /*删除文件*/
        case 4:
            printf("\t请输入文件名:");
            scanf("%s",filename);
            destroy(filename);
            printf("\n");
            break;
        /*打开文件*/
        case 5:
            printf("\t请输入文件名:");
            scanf("%s",filename);
            open_file(filename);
            printf("\n");
            break;
        /*关闭文件*/
        case 6:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            close_file(index);
            printf("\n");
            break;
        /*关闭文件*/
        case 7:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            printf("\t请输入指针偏移量:");
            scanf("%d",&number);
            lseek_file(index,number);
            printf("\n");
            break;
        /*读文件*/
        case 8:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            printf("\t请输入读取文件字节数目:");
            scanf("%d",&number);
            read_file(index,number);//将数据从文件写入BUFF
            printf("\n");
            break;
        /*写文件*/
        case 9:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            printf("\t请输入写入文件字节数目:");
            scanf("%d",&number);
            write_file(index,number);//将数据从BUFF写入文件
            printf("\n");
            break;
        /*请求帮助*/
        case 10:
            help();
            printf("\n");
            break;
        case 11:
            show_blk_map();
            printf("\n");
            break;
        case 12:
            show_inode_map();
            printf("\n");
            break;
        case 13:
            show_OpenFile();
            printf("\n");
            break;
        default:
            printf("%s command not found\n",comm);
        }
        if(quit) break;
    }
    close_fs();//关闭文件系统
    fclose(Disk);//关闭磁盘文件
    return 0;
}



四、程序总代码



IO.h

#ifndef IO_H_INCLUDED
#define IO_H_INCLUDED

#include <stdio.h>
/*自定义常量*/
#define C	                8//柱面总数
#define H	                8//磁头总数
#define B	                16//一个磁道的扇区数
#define L		            1024//扇区总数;L=C*H*B
#define DISK 		        "disk.txt"//磁盘文件
/*文件指针*/
FILE* Disk;
/*结构体*/
typedef struct
{
    char record[512];//每个扇区大小为512字节
} Sector; //扇区
/*模拟磁盘数组*/
Sector ldisk[C][H][B];//CHB 分别表示柱面号,磁头号和扇区号
/*IO函数*/
int FileToArray(void);//把文件内容恢复到数组
int ArrayToFile(void);//把数组ldisk 存储到文件
int read_block(int x, char *p, int strlen);//把逻辑块i的内容读入到指针p指向的内存位置,拷贝的字符个数为strlen
int write_block(int i, char *p, int strlen);//把指针p指向的内容写入逻辑块i,拷贝的字符个数为strlen
void intTOchar4(int x,char p[4]);//int类型转换为char[4]
int char4TOint(char p[4]);//char[4]转换为int


int FileToArray()
{
    int i,j,k;
    fseek(Disk,0,SEEK_SET);
    for(i=0; i<C; i++)
    {
        for(j=0; j<H; j++)
        {
            for(k=0; k<B; k++)
            {
                if(fread(&ldisk[i][j][k],512,1,Disk)!=1)
                {
                    printf("文件内容恢复到数组失败!\n");
                    k=B;
                    j=H;
                    i=C;//退出
                }
            }
        }
    }
    return 1;
}
int ArrayToFile()
{
    int i,j,k;
    fseek(Disk,0,SEEK_SET);
    for(i=0; i<C; i++)
    {
        for(j=0; j<H; j++)
        {
            for(k=0; k<B; k++)
            {
                if(fwrite(&ldisk[i][j][k],512,1,Disk)!=1)
                {
                    printf("数组存储到文件失败!\n");
                    k=B;
                    j=H;
                    i=C;//退出
                }
            }
        }
    }
    return 1;
}
int read_block(int x, char *p, int strlen)
{
    int i,j,k;
    i=x/(H*B);
    j=(x-i*H*B)/B;
    k=(x-i*H*B-j*B);
    strncpy(p, &ldisk[i][j][k], strlen);
    return 0;
}
int write_block(int x, char *p, int strlen)
{
    int i,j,k;
    i=x/(H*B);
    j=(x-i*H*B)/B;
    k=(x-i*H*B-j*B);
    strncpy(&ldisk[i][j][k], p, strlen);
    return 0;
}
void intTOchar4(int x,char p[4])
{
    int i=0;
    i=x%10;
    switch(i)
    {
    case 0:
        p[0]='0';
        break;
    case 1:
        p[0]='1';
        break;
    case 2:
        p[0]='2';
        break;
    case 3:
        p[0]='3';
        break;
    case 4:
        p[0]='4';
        break;
    case 5:
        p[0]='5';
        break;
    case 6:
        p[0]='6';
        break;
    case 7:
        p[0]='7';
        break;
    case 8:
        p[0]='8';
        break;
    case 9:
        p[0]='9';
        break;
    default:
        break;
    }
    x/=10;
    i=x%10;
    switch(i)
    {
    case 0:
        p[1]='0';
        break;
    case 1:
        p[1]='1';
        break;
    case 2:
        p[1]='2';
        break;
    case 3:
        p[1]='3';
        break;
    case 4:
        p[1]='4';
        break;
    case 5:
        p[1]='5';
        break;
    case 6:
        p[1]='6';
        break;
    case 7:
        p[1]='7';
        break;
    case 8:
        p[1]='8';
        break;
    case 9:
        p[1]='9';
        break;
    default:
        break;
    }
    x/=10;
    i=x%10;
    switch(i)
    {
    case 0:
        p[2]='0';
        break;
    case 1:
        p[2]='1';
        break;
    case 2:
        p[2]='2';
        break;
    case 3:
        p[2]='3';
        break;
    case 4:
        p[2]='4';
        break;
    case 5:
        p[2]='5';
        break;
    case 6:
        p[2]='6';
        break;
    case 7:
        p[2]='7';
        break;
    case 8:
        p[2]='8';
        break;
    case 9:
        p[2]='9';
        break;
    default:
        break;
    }
    x/=10;
    i=x%10;
    switch(i)
    {
    case 0:
        p[3]='0';
        break;
    case 1:
        p[3]='1';
        break;
    case 2:
        p[3]='2';
        break;
    case 3:
        p[3]='3';
        break;
    case 4:
        p[3]='4';
        break;
    case 5:
        p[3]='5';
        break;
    case 6:
        p[3]='6';
        break;
    case 7:
        p[3]='7';
        break;
    case 8:
        p[3]='8';
        break;
    case 9:
        p[3]='9';
        break;
    default:
        break;
    }
}
int char4TOint(char p[4])
{
    int x=0;
    x=(((p[3]-48)*10+(p[2]-48))*10+(p[1]-48))*10+p[0]-48;
    return x;
}
#endif // IO_H_INCLUDED



File.h

#ifndef FILE_H_INCLUDED
#define FILE_H_INCLUDED

#include "IO.h"

/*自定义常量*/
#define BlkNum		    512//磁盘块的数目(编号从0开始)
#define BlkSize		    1024//磁盘块大小为1K
#define InodeNum	    112//文件描述符数目
#define BlkPerNode	    4//每个文件包含的最大的磁盘块数目
#define K	            4//超级块占磁盘块数目(0\1\2\3)
#define SuperBlkBeg	    0//超级块起始磁盘块(0)
#define InodeBeg	    1//文件描述符起始磁盘块(1\2\3)
#define BlockDirBeg	    4//目录区起始磁盘块(4/5/6/7)
#define BlockFileBeg	8//文件区起始磁盘块
#define MaxDirNum	    112//目录所支持的最大的文件数
#define CommanNum	    (sizeof(command)/sizeof(char*))//指令数目
#define OpenFileMaximumNum  10//文件系统同时打开文件最大数目
/*指令集合*/
char* command[]= {"format","quit","directory","create","destroy","open","close","lseek","read","write","help","sbm","sim","sOF"};
/*路径名*/
char path[20]="file_system(yss)$ ";//文件系统(yss 袁少随)
/*读写缓冲区*/
char buffer[5000];
/*结构体*/
typedef struct
{
    char  blk_map[BlkNum];//磁盘块位图
    char  inode_map[InodeNum];//文件描述符位图
    char  blk_used[4];//已被使用的磁盘块数目
    char  inode_used[4];//已被使用的文件描述符数目
} SuperBlk;//超级块(保留区)
typedef struct
{
    char  blk_identifier[BlkPerNode][4];//占用的磁盘块编号
    char  blk_num[4];//占用的磁盘块数目
    char  file_size[4];//文件的大小
} Inode;//文件描述符
typedef struct
{
    char  name[20];//文件名
    char  inode_num[4];//文件描述符序号
} Dir;//目录
typedef struct
{
    int  pointer1;//读写指针(选择盘块)
    int  pointer2;//读写指针(盘块内偏移)
    char  name[30];//文件名
    int  inode_num;//文件描述符序号
} OpenFile;//已打开文件
/*自定义变量*/
SuperBlk	super_blk;//文件系统的超级块
Inode 	record_inode[InodeNum];//文件描述符使用情况
Dir 	dir_table[MaxDirNum];//目录使用情况
OpenFile    OpenFile_table[OpenFileMaximumNum];//已打开文件
int OpenFileNum=0;//已打开文件数目
/*子函数*/
void init_Dick();//初始化磁盘
int init_fs();//初始化文件系统
int close_fs();//关闭文件系统
int format_fs();//格式化文件系统
int create(char *filename);//根据指定的文件名创建新文件
int destroy(char *filename);//删除指定文件
int open_file(char *filename);//打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作
int close_file(int index);//关闭指定文件
int read_file(int index, int number);//从指定文件顺序读入number个字节到读写缓冲区buffer。读操作从文件的读写指针指示的位置开始
int write_file(int index, int number);//把读写缓冲区buffer的number个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始
/*把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,
它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置*/
int lseek_file(int index, int pos);
int directory();//列表显示所有文件及其长度
void help();//求助函数
void show_blk_map();//显示磁盘块使用情况,0代表未被使用,1代表已使用
void show_inode_map();//显示文件描述符使用情况,0代表未被使用,1代表已使用
void show_OpenFile();//显示已打开文件

/*File函数*/
void init_Dick()
{
    int i,j,k;
    for(i=0; i<C; i++)
    {
        for(j=0; j<H; j++)
        {
            for(k=0; k<B; k++)
            {
                memset(&ldisk[i][j][k], '#', 512);
            }
        }
    }
}
int init_fs()
{
    char judge;
    printf("    如果你是第一次使用此文件系统,请输入1!否则输入其它任意键!\n");
    scanf("%c",&judge);
    if(judge=='1')
    {
        format_fs();
        printf("\n");
    }
    FileToArray();//把文件内容恢复到数组
    //把数组内容恢复到程序内存中
    read_block(0,&super_blk,632);
    read_block(2,&record_inode,2688);
    read_block(8,&dir_table,4032);
    printf("\n");
    return 0;
}
int close_fs()
{
    //把程序内存中内容写入模拟磁盘数组
    write_block(0,&super_blk,632);
    write_block(2,&record_inode,2688);
    write_block(8,&dir_table,4032);
    ArrayToFile();//把数组ldisk 存储到文件
    return 0;
}
int format_fs()//格式化文件系统
{
    init_Dick();初始化磁盘数组
    char use[512];
    int i=0;
    memset(&super_blk.blk_map, '0', BlkNum);//初始化超级块
    memset(&super_blk.inode_map, '0', InodeNum);
    super_blk.blk_map[0]='1';
    super_blk.blk_map[1]='1';
    super_blk.blk_map[2]='1';
    super_blk.blk_map[3]='1';
    super_blk.blk_map[4]='1';
    super_blk.blk_map[5]='1';
    super_blk.blk_map[6]='1';
    super_blk.blk_map[7]='1';
    intTOchar4(8,super_blk.blk_used);
    super_blk.inode_map[0]='1';
    intTOchar4(1,super_blk.inode_used);
    for(i=0; i<InodeNum; i++)//初始化文件描述符使用情况
    {
        intTOchar4(BlkNum,record_inode[i].blk_identifier[0]);
        intTOchar4(BlkNum,record_inode[i].blk_identifier[1]);
        intTOchar4(BlkNum,record_inode[i].blk_identifier[2]);
        intTOchar4(BlkNum,record_inode[i].blk_identifier[3]);
        intTOchar4(0,record_inode[i].blk_num);
        intTOchar4(0,record_inode[i].file_size);
    }
    strncpy(dir_table[0].name,"yss_contents########",sizeof("yss_contents########")-1);//创建目录文件
    intTOchar4(0,dir_table[0].inode_num);
    intTOchar4(0,record_inode[0].blk_num);
    intTOchar4(0,record_inode[0].file_size);
    super_blk.inode_map[0]='1';
    for(i=1; i<MaxDirNum; i++)//初始化目录使用情况
    {
        intTOchar4(InodeNum,dir_table[i].inode_num);
        strncpy(dir_table[i].name,"!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
    }
    write_block(0,&super_blk,632);
    write_block(2,&record_inode,2688);
    write_block(8,&dir_table,2688);
    memset(&use, ' ', 512);
    for(i=16; i<L; i++)
    {
        write_block(i,use,512);
    }
    //printf("%d\n",sizeof(super_blk));
    //printf("%d\n",sizeof(record_inode));
    //printf("%d\n",sizeof(dir_table));
    ArrayToFile();
    printf("    格式化文件系统成功!\n");
    return 0;
}
int create(char *filename)//根据指定的文件名创建新文件
{
    int i;
    //printf("%d\n",strlen(filename));
    if(strlen(filename)>=20)
    {
        printf("    文件名过长!\n");
        return -1;
    }
    for(i=0; i<MaxDirNum; i++)
    {
        if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
        {
            printf("    文件系统中已存在该文件,请更换文件名或将已存在文件删除!\n");
            return -1;
        }
    }
    if(char4TOint(super_blk.inode_used)>=InodeNum)
    {
        printf("    文件系统中存储文件已达上限,请先删除一些不必要的文件后再创建新文件!\n");
        return -1;
    }
    strncpy(dir_table[char4TOint(super_blk.inode_used)].name,filename,strlen(filename));
    for(i=1; i<InodeNum; i++)
    {
        if(super_blk.inode_map[i]=='0')
        {
            intTOchar4(i,dir_table[char4TOint(super_blk.inode_used)].inode_num);
            intTOchar4(0,record_inode[i].blk_num);
            intTOchar4(0,record_inode[i].file_size);
            super_blk.inode_map[i]='1';
            break;
        }
    }
    i=char4TOint(super_blk.inode_used)+1;
    intTOchar4(i,super_blk.inode_used);
    printf("    文件%s创建成功!\n",filename);
    return 0;
}
int destroy(char *filename)//删除指定文件
{
    int i,j,k;
    char use[512];
    for(i=0; i<OpenFileNum; i++)
    {
        if(strcmp(OpenFile_table[i].name, filename)==0)
        {
            printf("    %s文件已打开,请先关闭文件后再进行删除。\n",filename);
            return -1;
        }
    }
    for(i=1; i<MaxDirNum; i++)
    {
        if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
        {
            strncpy(dir_table[i].name, "!!!!!!!!!!!!!!!!!!!!",sizeof("!!!!!!!!!!!!!!!!!!!!")-1);
            intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].file_size);
            if(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num)!=0)
            {
                memset(&use, ' ', 512);
                //printf("%d\n",char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0]));
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[0])*2+1,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[1])*2+1,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[2])*2+1,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2,use,512);
                write_block(char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[3])*2+1,use,512);
                k = char4TOint(super_blk.blk_used)-4;
                intTOchar4(k,super_blk.blk_used);
            }
            for(j=0; j<char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_num); j++)
            {
                super_blk.blk_map[char4TOint(record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j])]='0';
                intTOchar4(BlkNum,record_inode[char4TOint(dir_table[i].inode_num)].blk_identifier[j]);
            }
            intTOchar4(0,record_inode[char4TOint(dir_table[i].inode_num)].blk_num);
            super_blk.inode_map[char4TOint(dir_table[i].inode_num)]='0';
            intTOchar4(InodeNum,dir_table[i].inode_num);
            i=char4TOint(super_blk.inode_used)-1;
            intTOchar4(i,super_blk.inode_used);

            printf("    %s文件已删除!\n",filename);
            break;
        }
    }
    if(i==MaxDirNum)
    {
        printf("    没有在目录中找到该文件,请确保输入的文件名正确!\n");
    }
    return 0;
}
int open_file(char *filename)//打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作
{
    int i;
    if(OpenFileNum>OpenFileMaximumNum)
    {
        printf("    此时已打开文件数目达到文件系统最大要求,如要继续打开此文件,请先关闭一些不再使用的文件!\n");
        return -1;
    }
    for(i=0; i<MaxDirNum; i++)
    {
        if(strncmp(dir_table[i].name, filename,strlen(filename))==0&&dir_table[i].name[strlen(filename)]=='!')
        {
            strcpy(OpenFile_table[OpenFileNum].name, filename);
            OpenFile_table[OpenFileNum].inode_num = char4TOint(dir_table[i].inode_num);
            OpenFileNum++;
            printf("    %s文件已打开,文件索引号为%d。\n",filename,char4TOint(dir_table[i].inode_num));
            break;
        }
    }
    if(i==MaxDirNum)
    {
        printf("    没有在目录中找到该文件,请确保输入的文件名正确!\n");
    }
    return char4TOint(dir_table[i].inode_num);
}
int close_file(int index)//关闭指定文件
{
    int i=0,j=0,judge=0;
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            printf("    %s文件已关闭。\n",OpenFile_table[i].name);
            for(j=i; j<OpenFileNum-1; j++)
            {
                OpenFile_table[j].inode_num = OpenFile_table[j+1].inode_num;
                strcpy(OpenFile_table[j].name, OpenFile_table[j+1].name);
                OpenFile_table[j].pointer1 = OpenFile_table[j+1].pointer1;
                OpenFile_table[j].pointer2 = OpenFile_table[j+1].pointer2;
            }
            OpenFile_table[j].inode_num = InodeNum;
            strcpy(OpenFile_table[j].name, "\0");
            OpenFile_table[j].pointer1 = 0;
            OpenFile_table[j].pointer2 = 0;
            OpenFileNum--;
            judge = 1;
            break;
        }
    }
    if(judge==0)
    {
        printf("    没有在已打开文件中找到该文件,请确保输入的索引号正确!\n");
    }
    return 0;
}
/*把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,
它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置*/
int lseek_file(int index, int pos)
{
    int i=0;
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            if(char4TOint(record_inode[index].file_size) == 0)
            {
                printf("    该文件尚未存储任何内容,不允许偏移读写指针!\n");
            }
            else
            {
                if(char4TOint(record_inode[index].file_size) < pos)
                {
                    printf("    该文件允许偏移读写指针最大为%d,指针偏移失败 !\n",char4TOint(record_inode[index].file_size));
                }
                else
                {
                    OpenFile_table[i].pointer1 = pos/1024;
                    OpenFile_table[i].pointer2 = pos%1024;
                }
            }
            break;
        }
    }
    if(i==OpenFileNum)
    {
        printf("    索引号所对应的文件没有被打开,请先打开该文件!\n");
    }
    return 0;
}
int read_file(int index, int number)//从指定文件顺序读入number个字节到读写缓冲区buffer。读操作从文件的读写指针指示的位置开始
{
    int i=0,j=0,x=0,y=0;
    char use[8][512];
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            if(char4TOint(record_inode[index].file_size) == 0)
            {
                printf("    该文件为空!\n");
            }
            else
            {
                read_block(char4TOint(record_inode[index].blk_identifier[0])*2,  use[0],512);
                read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
                read_block(char4TOint(record_inode[index].blk_identifier[1])*2,  use[2],512);
                read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
                read_block(char4TOint(record_inode[index].blk_identifier[2])*2,  use[4],512);
                read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
                read_block(char4TOint(record_inode[index].blk_identifier[3])*2,  use[6],512);
                read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
                x = OpenFile_table[i].pointer1*2;
                if(OpenFile_table[i].pointer2>512)
                {
                    x++;
                    y = OpenFile_table[i].pointer2 - 512;
                }
                else
                {
                    y = OpenFile_table[i].pointer2;
                }
                if((char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
                {
                    for(j=0; j<=(char4TOint(record_inode[index].file_size)-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
                    {
                        buffer[j] = use[x][y];
                        y++;
                        if(y==512)
                        {
                            x++;
                            y=0;
                        }
                    }
                    printf("    文件内容已读入到末尾,共读取%d个字节!\n",j);
                    buffer[j++]='\0';
                }
                else
                {
                    for(j=0; j<=number; j++)
                    {
                        buffer[j] = use[x][y];
                        y++;
                        if(y==512)
                        {
                            x++;
                            y=0;
                        }
                    }
                    buffer[j++]='\0';
                }
                printf("    文件内容已读入到读写缓冲区buffer中!内容为:\n\t\t%s\n",&buffer);
                lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
            }
            break;
        }
    }
    if(i==OpenFileNum)
    {
        printf("    索引号所对应的文件没有被打开,请先打开该文件!\n");
    }
    return 0;
}
int write_file(int index, int number)//把读写缓冲区buffer的number个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始
{
    int i=0,j=0,k=0,x=0,y=0,z=0,w;
    char use[8][512];
    for(i=0; i<OpenFileNum; i++)
    {
        if(OpenFile_table[i].inode_num == index)
        {
            printf("    请输入你想写入该文件的内容:\n\t");
            for(j=0; j<=number; j++)
            {
                scanf("%c",&buffer[j]);
            }
            if(char4TOint(record_inode[index].blk_num)==0)
            {
                intTOchar4(4,record_inode[index].blk_num);
                for(z=0; z<4; z++)
                {
                    for(k=0; k<BlkNum; k++)
                    {
                        if(super_blk.blk_map[k]=='0')
                        {
                            intTOchar4(k,record_inode[index].blk_identifier[z]);
                            super_blk.blk_map[k]='1';
                            break;
                        }
                    }
                }
                w=char4TOint(super_blk.blk_used)+4;
                intTOchar4(w,super_blk.blk_used);
            }
            read_block(char4TOint(record_inode[index].blk_identifier[0])*2,  use[0],512);
            read_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
            read_block(char4TOint(record_inode[index].blk_identifier[1])*2,  use[2],512);
            read_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
            read_block(char4TOint(record_inode[index].blk_identifier[2])*2,  use[4],512);
            read_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
            read_block(char4TOint(record_inode[index].blk_identifier[3])*2,  use[6],512);
            read_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
            x = OpenFile_table[i].pointer1*2;
            if(OpenFile_table[i].pointer2>512)
            {
                x++;
                y = OpenFile_table[i].pointer2 - 512;
            }
            else
            {
                y = OpenFile_table[i].pointer2;
            }
            if((4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)) < number)
            {
                for(j=0; j<=(4096-(OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2)); j++)
                {
                    use[x][y] = buffer[j];
                    y++;
                    if(y==512)
                    {
                        x++;
                        y=0;
                    }
                }
                printf("    文件内容未全部写入指定文件中,文件内容已达到最大值,写入%d个字节!\n",j);
            }
            else
            {
                for(j=0; j<=number; j++)
                {
                    use[x][y] = buffer[j];
                    y++;
                    if(y==512)
                    {
                        x++;
                        y=0;
                    }
                    //printf("%c",use[x][y]);
                }
                printf("    文件内容已全部写入指定文件中!\n");
            }
            //printf("%d\n",j);
            w = char4TOint(record_inode[index].file_size)+j;
            intTOchar4(w,record_inode[index].file_size);
            write_block(char4TOint(record_inode[index].blk_identifier[0])*2,  use[0],512);
            write_block(char4TOint(record_inode[index].blk_identifier[0])*2+1,use[1],512);
            write_block(char4TOint(record_inode[index].blk_identifier[1])*2,  use[2],512);
            write_block(char4TOint(record_inode[index].blk_identifier[1])*2+1,use[3],512);
            write_block(char4TOint(record_inode[index].blk_identifier[2])*2,  use[4],512);
            write_block(char4TOint(record_inode[index].blk_identifier[2])*2+1,use[5],512);
            write_block(char4TOint(record_inode[index].blk_identifier[3])*2,  use[6],512);
            write_block(char4TOint(record_inode[index].blk_identifier[3])*2+1,use[7],512);
            lseek_file(index,OpenFile_table[i].pointer1*1024+OpenFile_table[i].pointer2);
        }
        break;
    }
    if(i==OpenFileNum)
    {
        printf("    索引号所对应的文件没有被打开,请先打开该文件!\n");
    }
    return 0;
}
int directory()//显示所有文件及其长度,以及占用磁盘号
{
    int i=0,j=0,k=0,x=0;
    if(char4TOint(super_blk.inode_used)==1)
    {
        printf("    文件系统未含有文件!\n");
    }
    else
    {
        for(i=1; i<InodeNum; i++)
        {
            if(super_blk.inode_map[i]=='1')
            {
                for(j=0; j<MaxDirNum; j++)
                {
                    if(char4TOint(dir_table[j].inode_num)==i)
                        break;
                }
                printf("    文件名为:");
                for(x=0; x<20; x++)
                {
                    if(dir_table[j].name[x]!='!')
                        printf("%c",dir_table[j].name[x]);
                }
                printf("     文件大小为:%d字节\n",char4TOint(record_inode[i].file_size));
                if(char4TOint(record_inode[i].blk_num)==0)
                {
                    printf("    文件未占用磁盘块!");
                }
                else
                {
                    printf("    文件占用的磁盘块编号为: ");
                    for(k=0; k<char4TOint(record_inode[i].blk_num); k++)
                        printf("%d ",char4TOint(record_inode[i].blk_identifier[k]));
                }
                printf("\n\n");
            }
        }
    }
    return 0;
}
void help()
{
    printf("***********************************************************************************\n");
    printf("* 下面是本文件系统所支持的命令:                                                  *\n");
    printf("*           格式化文件系统:     format                                           *\n");
    printf("*           退出文件系统:       quit                                             *\n");
    printf("*           显示目录内容:       directory                                        *\n");
    printf("*           创建文件:           create                                           *\n");
    printf("*           删除文件:           destroy                                          *\n");
    printf("*           打开文件:           open                                             *\n");
    printf("*           关闭文件:           close                                            *\n");
    printf("*           文件指针偏移:       lseek                                            *\n");
    printf("*           读文件:             read                                             *\n");
    printf("*           写文件:             write                                            *\n");
    printf("*           请求帮助:           help                                             *\n");
    printf("*           磁盘块使用情况:     sbm                                              *\n");
    printf("*           文件描述符使用情况: sim                                              *\n");
    printf("*           已打开文件列表:     sOF                                              *\n");
    printf("***********************************************************************************\n");
}
void show_blk_map()//显示磁盘块使用情况,0代表未被使用,1代表已使用
{
    int i=0;
    for(i=0; i<BlkNum; i++)
    {
        printf("%c   ",super_blk.blk_map[i]);
        if((i+1)%24==0)
            printf("\n");
    }
    printf("\n\t已被使用的磁盘块数目为:%d\n",char4TOint(super_blk.blk_used));
}
void show_inode_map()//显示文件描述符使用情况,0代表未被使用,1代表已使用
{
    int i=0;
    for(i=0; i<InodeNum; i++)
    {
        printf("%c   ",super_blk.inode_map[i]);
        if((i+1)%24==0)
            printf("\n");
    }
    printf("\n\t已被使用的文件描述符数目为:%d\n",char4TOint(super_blk.inode_used));
}
void show_OpenFile()//显示已打开文件
{
    int i=0;
    if(OpenFileNum == 0)
    {
        printf("\t未打开任何文件!\n");
    }
    else
    {
        printf("\t已打开%d个文件,分别是:\n",OpenFileNum);
        for(i=0; i<OpenFileNum; i++)
        {
            printf("\t\t文件名为%s,该文件索引号为%d.",OpenFile_table[i].name,OpenFile_table[i].inode_num);
        }
    }
}
#endif // FILE_H_INCLUDED



main.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "file.h"
#include "IO.h"

/*主函数*/
int main()
{
    printf("***********************************************************************************\n");
    printf("* 欢迎来到yss的文件系统!!!                                                     *\n");
    printf("* 介绍:此文件系统是模拟Linux系统所制作,在这里你将体验到命令行的乐趣!           *\n");
    printf("*           格式化文件系统:     format                                           *\n");
    printf("*           退出文件系统:       quit                                             *\n");
    printf("*           显示目录内容:       directory                                        *\n");
    printf("*           创建文件:           create                                           *\n");
    printf("*           删除文件:           destroy                                          *\n");
    printf("*           打开文件:           open                                             *\n");
    printf("*           关闭文件:           close                                            *\n");
    printf("*           文件指针偏移:       lseek                                            *\n");
    printf("*           读文件:             read                                             *\n");
    printf("*           写文件:             write                                            *\n");
    printf("*           请求帮助:           help                                             *\n");
    printf("*           磁盘块使用情况:     sbm                                              *\n");
    printf("*           文件描述符使用情况: sim                                              *\n");
    printf("*           已打开文件列表:     sOF                                              *\n");
    printf("* 好了!现在请开始你的表演!!!                                                  *\n");
    printf("***********************************************************************************\n");
    char comm[30],filename[20];
    int i,quit=0,choice,index,number;
    Disk = fopen(DISK,"r+");//打开磁盘文件
    if(Disk == NULL)
    {
        printf("打开磁盘文件失败,请查看是否已创建disk.txt!\n");
    }
    init_fs();//初始化文件系统
    while(1)
    {
        printf("%s ",path);
        scanf("%s",comm);
        choice=-1;
        for(i=0; i<CommanNum; ++i)
        {
            if(strcmp(comm,command[i])==0)
            {
                choice=i;
                break;
            }
        }
        switch(choice)
        {
        /*格式化文件系统*/
        case 0:
            format_fs();
            printf("\n");
            break;
        /*退出文件系统*/
        case 1:
            quit=1;
            break;
        /*显示目录内容*/
        case 2:
            directory();
            printf("\n");
            break;
        /*创建文件*/
        case 3:
            printf("\t请输入文件名:");
            scanf("%s",filename);
            create(filename);
            printf("\n");
            break;
        /*删除文件*/
        case 4:
            printf("\t请输入文件名:");
            scanf("%s",filename);
            destroy(filename);
            printf("\n");
            break;
        /*打开文件*/
        case 5:
            printf("\t请输入文件名:");
            scanf("%s",filename);
            open_file(filename);
            printf("\n");
            break;
        /*关闭文件*/
        case 6:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            close_file(index);
            printf("\n");
            break;
        /*关闭文件*/
        case 7:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            printf("\t请输入指针偏移量:");
            scanf("%d",&number);
            lseek_file(index,number);
            printf("\n");
            break;
        /*读文件*/
        case 8:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            printf("\t请输入读取文件字节数目:");
            scanf("%d",&number);
            read_file(index,number);//将数据从文件写入BUFF
            printf("\n");
            break;
        /*写文件*/
        case 9:
            printf("\t请输入文件索引号:");
            scanf("%d",&index);
            printf("\t请输入写入文件字节数目:");
            scanf("%d",&number);
            write_file(index,number);//将数据从BUFF写入文件
            printf("\n");
            break;
        /*请求帮助*/
        case 10:
            help();
            printf("\n");
            break;
        case 11:
            show_blk_map();
            printf("\n");
            break;
        case 12:
            show_inode_map();
            printf("\n");
            break;
        case 13:
            show_OpenFile();
            printf("\n");
            break;
        default:
            printf("%s command not found\n",comm);
        }
        if(quit) break;
    }
    close_fs();//关闭文件系统
    fclose(Disk);//关闭磁盘文件
    return 0;
}



五、实验结果


格式化文件系统:


在这里插入图片描述


显示磁盘块使用情况:


在这里插入图片描述


显示文件描述符使用情况:


在这里插入图片描述


帮助界面:


在这里插入图片描述


创建文件:


在这里插入图片描述


打开文件:


在这里插入图片描述


写文件:


在这里插入图片描述


读文件:


在这里插入图片描述


关闭文件:


在这里插入图片描述


删除文件:


在这里插入图片描述



六、实验体会

历时12天,终于完工。为自己点赞!

本次实验代码完全由本人(yss)一键一键所敲,程序运行起来指令十分简单,但或许还有一些不足之处,请各位在博客下多多批评指正,感谢!

通过本次模拟操作系统实验,我熟悉并掌握了真实情况下文件系统的运作方式,可能不同系统或不同版本的文件系统存在细节上的差异,但大体规律还是类似的。在真实磁盘上只有0和1,而我使用一个文件(Disk.txt,大小512KB)模拟真实磁盘,使用ASCII码来代替0和1,操作起来会相对简单一些(但其实还是比较难的,可能是自己太菜)。本次实验使我了解了文件系统的结构以及它的工作原理,了解文件系统的read,write等函数的实现,对操作系统有了更深一步的理解,获益匪浅。


如有感兴趣或想要了解更多的同学,请点击(里面有程序演示视频):



https://github.com/yuanshaosui/OS/tree/master/文件系统



欢迎各位同学的留言.



版权声明:本文为yuanshaosui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。