#include 'stdio.h'
#include <stdlib.h>
#include <conio.h>
#include <string.h>

int physic[300];        // 文件地址缓冲区,用于存储文件的物理地址
int style=1;            // 文件的类型,1表示文本文件,2表示二进制文件

char cur_dir[10]='c';   // 当前目录,初始值为'c'

struct command         // 命令结构体
{
    char com[10];       // 命令名称
}cmd[12];

struct block           // 盘块结构体,用于模拟磁盘的存储空间 
{
    int n;              // 空闲的盘块的个数
    int free[50];       // 存放空闲盘块的地址
    int a;              // 模拟盘块是否被占用,0表示未被占用,1表示被占用
}memory[200];

struct block_super     // 超级块结构体,用于存储空闲盘块的信息 
{
    int n;              // 空闲的盘块的个数
    int free[50];       // 存放进入栈中的空闲块
    int stack[50];      // 存放下一组空闲盘块的地址
}super_block;

struct node             // i结点结构体,用于存储文件的相关信息
{
    int file_style;     // i结点文件类型,1表示文本文件,2表示二进制文件
    int file_length;    // i结点文件长度,即文件占用的盘块数
    int file_address[100];  // i结点文件的物理地址,即文件所占用的盘块的地址
} i_node[64];

struct dir              // 目录项结构体,用于存储文件的目录信息
{
    char file_name[10]; // 文件名
    int  i_num;         // 文件的结点号
    char dir_name[10];  // 文件所在的目录
} c[64];

void format()           // 格式化函数,用于初始化文件系统
{
    int i,j,k;
    super_block.n=50;   // 超级块中空闲盘块的个数初始值为50
    for(i=0;i<50;i++)   // 初始化超级块
    {
        super_block.free[i]=i;  // 存放进入栈中的空闲块
        super_block.stack[i]=50+i; // 存放下一组的盘块
    }

    for(i=0;i<64;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<64;i++)   // 初始化根目录区信息
    {
        strcpy(c[i].file_name,'');          // 文件名
        c[i].i_num=-1;                      // 文件的结点号
        strcpy(c[i].dir_name,'');           // 文件所在的目录
    }

    for(i=0;i<200;i++)  // 初始化存储空间
    {
        memory[i].n=0;      // 必须有这个
        memory[i].a=0;      
        for(j=0;j<50;j++)
        {
            memory[i].free[j]=-1;  // 存放空闲盘块的地址
        }
    }

    for(i=0;i<200;i++)  // 将空闲块的信息用成组链接的方法写进每组的最后一个块中
    {                   // 存储空间初始化
        if((i+1)%50==0) // 每50个盘块为一组
        {
            k=i+1;
            for(j=0;j<50;j++)
            {
                if(k<200)
                {
                    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');    // 打开名为system的二进制文件,以写入方式打开
 for(i=0;i<200;i++)          // 循环200次,将内存中的200个块写入文件
 {
  fwrite(&memory[i],sizeof(struct block),1,fp);    // 将内存中的一个块写入文件,每次写入一个块的大小
 }
 fwrite(&super_block,sizeof(struct block_super),1,fp);    // 将超级块写入文件

 for(i=0;i<64;i++)          // 循环64次,将i节点写入文件
 {
 fwrite(&i_node[i],sizeof(struct node),1,fp);    // 将一个i节点写入文件,每次写入一个i节点的大小
 }
 for(i=0;i<64;i++)          // 循环64次,将目录项写入文件
 {
 fwrite(&c[i],sizeof(struct dir),1,fp);    // 将一个目录项写入文件,每次写入一个目录项的大小
 }
 fclose(fp);                // 关闭文件
}

void read_file(FILE *fp)   /* 读出系统文件的信息 */
{
 int i;
 fp=fopen('system','rb');    // 打开名为system的二进制文件,以读取方式打开
 for(i=0;i<200;i++)          // 循环200次,将文件中的200个块读入内存
 {
  fread(&memory[i],sizeof(struct block),1,fp);    // 从文件中读取一个块,每次读取一个块的大小
 }

 fread(&super_block,sizeof(struct block_super),1,fp);    // 从文件中读取超级块

 for(i=0;i<64;i++)          // 循环64次,将i节点读入内存
 {
  fread(&i_node[i],sizeof(struct node),1,fp);    // 从文件中读取一个i节点,每次读取一个i节点的大小
 }

 for(i=0;i<64;i++)          // 循环64次,将目录项读入内存
 {
  fread(&c[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--)    // 循环length次,回收length个盘块
 {
  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++)    // 循环50次,将栈中的50个盘块号写入下一个文件地址中
   {
    memory[k].free[j]=super_block.free[j];    // 将栈中的盘块号写入下一个文件地址中
   }
   super_block.n=0;    // 栈中的盘块号已经全部写入下一个文件地址中,将栈中盘块数清零
   memory[k].n=50;    // 将下一个文件地址中的盘块数设置为50
  }
  memory[k].a=0;    // 将要回收的盘块标记为未使用
  if(m==-1)
  {
   m=49;      /* 将下一个文件地址中的盘块号回收到栈底中,这个地址中存放着刚才满栈的地址

信息  */
  }
  super_block.free[m]=physic[i]; /* 将下一个文件地址中的盘块号回收到栈中 */
  super_block.n++;    // 栈中的盘块数加1
 }
}

void allot(int length)     /* 分配空间 */
{
 int i,j,k,m,p;
 for(i=0;i<length;i++)    // 循环length次,分配length个盘块
 {
  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++;    // 栈中的盘块数加1
   }
   continue;     /* 要跳过这次循环,下面的语句在IF中已经执行过 */
  }
  physic[i]=m;     /* 栈中的相应盘块的地址写进 文件地址缓冲区 */
  memory[m].a=1;    // 将分配的盘块标记为已使用
  super_block.n--;    // 栈中的盘块数减1
 }
}

void create_file(char filename[],int length) /* 创建文件 */
{
 int i,j;
 for(i=0;i<64;i++)    // 循环64次,查找是否有同名文件
 {
  if(strcmp(filename,c[i].file_name)==0)    // 如果找到同名文件
  {
   printf('文件已经存在,不允许建立重名的文件\n');    // 输出错误信息
   return;    // 返回
  }
 }
 for(i=0;i<64;i++)    // 循环64次,查找空闲的目录项
 {
   if(c[i].i_num==-1)    // 如果找到空闲的目录项
   {
    c[i].i_num=i;    // 将目录项的i节点号设置为i
    strcpy(c[i].file_name,filename);    // 将文件名写入目录项
    strcpy(c[i].dir_name,cur_dir);    // 将当前目录名写入目录项
    i_node[i].file_style=style;    // 将文件类型写入i节点
    i_node[i].file_length=length;    // 将文件长度写入i节点
    allot(length);    // 分配盘块
    for(j=0;j<length;j++)    // 循环length次,将盘块号写入i节点
    {
     i_node[i].file_address[j]=physic[j];
    }
    break;    // 跳出循环
   }
 }
}

void create_dir(char filename[])    /* 创建目录 */
{
 style=0;         /* 0代表文件类型是目录文件 */
 create_file(filename,4);    // 创建文件,长度为4
 style=1;         /* 用完恢复初值,因为全局变量,否则 */
}

void show_dir()    /* 显示目录内容 */
{
 int i,j,k;
 printf('\n当前目录为:/%s\n',cur_dir);    // 输出当前目录名
 printf('\n文件名\t文件类型\t文件长度\n');
 for(i=0;i<64;i++)    // 循环64次,查找当前目录下的文件
 {
  if(strcmp(cur_dir,c[i].dir_name)==0)    // 如果找到当前目录下的文件
  {
   printf('%s\t',c[i].file_name);    // 输出文件名
   if(i_node[c[i].i_num].file_style==1)    // 如果文件类型为文本文件
   {
    printf('txt\t\t');    // 输出文件类型
   }
   else
   {
    printf('bin\t\t');
   }
   printf('%d\n',i_node[c[i].i_num].file_length);    // 输出文件长度
  }
 }
 printf('\n');
}

void delete_file(char filename[])    /* 删除文件 */
{
 int i,j,k,length;
 for(i=0;i<64;i++)    // 循环64次,查找要删除的文件
 {
  if(strcmp(filename,c[i].file_name)==0&&strcmp(cur_dir,c[i].dir_name)==0)    // 如果找到要删除的文件
  {
   length=i_node[c[i].i_num].file_length;    // 获取文件长度
   callback(length);    // 回收磁盘空间
   for(j=0;j<100;j++)    // 循环100次,将i节点中的文件地址清零
   {
    i_node[c[i].i_num].file_address[j]=-1;
   }
   i_node[c[i].i_num].file_length=-1;    // 将i节点中的文件长度清零
   i_node[c[i].i_num].file_style=-1;    // 将i节点中的文件类型清零
   strcpy(c[i].file_name,'');    // 将目录项中的文件名清零
   c[i].i_num=-1;    // 将目录项中的i节点号清零
   break;    // 跳出循环
  }
 }
}

void delete_dir(char filename[])    /* 删除目录 */
{
 int i,j,k,length;
 for(i=0;i<64;i++)    // 循环64次,查找要删除的目录
 {
  if(strcmp(filename,c[i].file_name)==0&&strcmp(cur_dir,c[i].dir_name)==0&&i_node[c[i].i_num].file_style==0)    // 如果找到要删除的目录
  {
   for(j=0;j<64;j++)    // 循环64次,查找要删除的目录下的文件
   {
    if(strcmp(c[j].dir_name,filename)==0)    // 如果找到要删除的目录下的文件
    {
     length=i_node[c[j].i_num].file_length;    // 获取文件长度
     callback(length);    // 回收磁盘空间
     for(k=0;k<100;k++)    // 循环100次,将i节点中的文件地址清零
     {
      i_node[c[j].i_num].file_address[k]=-1;
     }
     i_node[c[j].i_num].file_length=-1;    // 将i节点中的文件长度清零
     i_node[c[j].i_num].file_style=-1;    // 将i节点中的文件类型清零
     strcpy(c[j].file_name,'');    // 将目录项中的文件名清零
     c[j].i_num=-1;    // 将目录项中的i节点号清零
    }
   }
   length=i_node[c[i].i_num].file_length;    // 获取目录文件长度
   callback(length);    // 回收磁盘空间
   for(j=0;j<100;j++)    // 循环100次,将i节点中的文件地址清零
   {
    i_node[c[i].i_num].file_address[j]=-1;
   }
   i_node[c[i].i_num].file_length=-1;    // 将i节点中的文件长度清零
   i_node[c[i].i_num].file_style=-1;   
  }
 }
}

int main()
{
 FILE *fp;
 format();
 read_file(fp);
 while(1)
 {
  printf('请输入命令:');
  scanf('%s',cmd[0].com);
  if(strcmp(cmd[0].com,'create')==0)
  {
   printf('请输入文件名:');
   scanf('%s',cmd[1].com);
   printf('请输入文件类型:1表示文本文件,2表示二进制文件');
   scanf('%d',&style);
   printf('请输入文件长度:');
   scanf('%d',&cmd[2].com[0]);
   create_file(cmd[1].com,cmd[2].com[0]);
  }
  if(strcmp(cmd[0].com,'show')==0)
  {
   show_dir();
  }
  if(strcmp(cmd[0].com,'delete')==0)
  {
   printf('请输入要删除的文件名:');
   scanf('%s',cmd[1].com);
   delete_file(cmd[1].com);
  }
  if(strcmp(cmd[0].com,'mkdir')==0)
  {
   printf('请输入要创建的目录名:');
   scanf('%s',cmd[1].com);
   create_dir(cmd[1].com);
  }
  if(strcmp(cmd[0].com,'rmdir')==0)
  {
   printf('请输入要删除的目录名:');
   scanf('%s',cmd[1].com);
   delete_dir(cmd[1].com);
  }
  write_file(fp);
 }
 return 0;
}

代码功能:

  1. 格式化文件系统: format() 函数初始化文件系统,分配磁盘空间,并设置超级块、i节点和目录项的初始状态。
  2. 创建文件: create_file() 函数根据文件名、文件类型和文件长度创建文件,分配磁盘空间并将文件信息写入 i节点和目录项。
  3. 创建目录: create_dir() 函数创建目录,实际上是创建了一个特殊的文件,其类型为目录,长度为4。
  4. 显示目录内容: show_dir() 函数显示当前目录下的所有文件和目录信息。
  5. 删除文件: delete_file() 函数根据文件名删除文件,释放磁盘空间并将文件信息从 i节点和目录项中清除。
  6. 删除目录: delete_dir() 函数根据目录名删除目录,实际上是删除目录文件,并将目录下的所有文件和目录删除。

代码使用:

  1. 编译: 使用 C 语言编译器编译代码,例如 GCC 编译器:gcc file_system.c -o file_system
  2. 运行: 运行编译后的可执行文件 ./file_system
  3. 输入命令: 根据提示输入命令,例如 create file1 10 创建一个名为 file1 的文本文件,长度为 10 个磁盘块。

注意:

  • 该代码实现了一个简化的文件系统,只支持基本的文件操作,没有实现文件内容的读写功能。
  • 磁盘空间分配算法简单,仅使用一个简单的栈结构来管理空闲盘块,没有考虑碎片问题。
  • 代码中使用了一些硬编码的值,例如磁盘块大小、i节点个数等,可根据实际情况进行修改。

改进方向:

  • 实现文件内容的读写功能。
  • 使用更先进的磁盘空间分配算法,例如最佳适配算法或最坏适配算法。
  • 增加用户权限管理功能。
  • 使用更复杂的目录结构,支持多级目录。
  • 实现文件系统镜像备份和恢复功能。

代码示例:

请输入命令: create file1 10
请输入文件类型:1表示文本文件,2表示二进制文件 1
请输入文件长度: 10

请输入命令: show

当前目录为:/c

文件名	文件类型	文件长度
file1	txt		10

请输入命令: delete file1

请输入命令: show

当前目录为:/c

文件名	文件类型	文件长度

请输入命令: mkdir dir1

请输入命令: show

当前目录为:/c

文件名	文件类型	文件长度
dir1	bin		4

请输入命令: rmdir dir1

请输入命令: show

当前目录为:/c

文件名	文件类型	文件长度

C语言实现简易UNIX文件系统模拟

原文地址: https://www.cveoy.top/t/topic/f2r9 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录