当前位置:文档之家› 操作系统 实验报告 文件管理

操作系统 实验报告 文件管理

昆明理工大学信息工程与自动化学院学生实验报告(201 —201 学年第二学期)课程名称:操作系统开课实验室:年月日一、实验目的用C或C++语言编写和调试一个简单的文件系统,模拟文件管理的基本功能。

从而对各种文件操作命令的实质内容和执行过程有比较深入的了解。

二、实验原理及基本技术路线图(方框原理图)用C模拟实现文件系统的管理;要求设计一个多级目录结构的文件系统,能正确描述文件控制块,采用合理的外存分配方式,能实现基本的目录及文件的操作,包括创建、删除、重命名、复制、移动等功能,并对文件有一定的存取权限控制。

功能设计:Help 显示命令帮助dir 显示当前目录下的文件和文件夹exit 退出系统create [文件名] 创建文本文件cdir [目录名] 创建文件夹read [文件名] 读取一个文件最多可同时读取五个close[文件名] 关闭一个文件edit [文件名] 编辑一个文件cd [目录名] 进子目录或者上级目录attr [文件名] 显示该文件的属性del [文件名] 删除文件rename [文件名] 重命名编辑功能流程图删除文件流程图创建文件流程图核心算法:bool Format(void); //格式化bool install(void); //装载虚拟硬盘的数据void login(void); /用户登陆void showMenu(void);//显示功能菜单bool onAction(void);//用户选择功能并执行void createFile(string str);//创建文件bool read(string str);//读取文件void editFile(string str);//编辑文件void Delete(string str);//删除一个文件数据结构:/*---------常变量------*/const unsigned int BLOCK_SIZE=512; //块长const unsigned int DATA_BLOCK_NUM=512; //数据块数量const unsigned int DINODE_START=4*BLOCK_SIZE; //inode起始位置const unsigned int DINODE_SIZE=512; //inode大小const unsigned int DINODE_NUM=32; //inode数量const unsigned int DATASTART=(2+DINODE_NUM)*BLOCK_SIZE; //数据区的开始地址const unsigned int ACCOUNT_NUM=10; //用户数量/*inode结构体*/struct inode{unsigned short di_tag; /*inode标识*/unsigned short di_number; /*关联文件数,当为0时表示删除文件,如一个目录至少包含两个文件:"."和".."*/unsigned short di_mode; /*存取模式:0为目录,1为文件*/unsigned short di_userID; /*当前inode所属用户0为根目录ID,一次下去是管理员目录、用户目录*/unsigned short di_access; /*访问权限0为不允许普通用户访问(公共目录),1为允许普通用户访问*/unsigned short di_size; /*文件大小,目录没有大小,值为0*/unsigned short di_ctime; /* 创建时间*/unsigned short di_mtime; /* 最后一次修改时间*/unsigned short di_block[DATA_BLOCK_NUM]; /* 数据块块地址编号*/};/**超级块***/struct super_block{unsigned short s_inodes_count; /* 文件系统中inode的总数*/unsigned short s_blocks_count; /* 数据块总数*/unsigned short s_r_blocks_count; /* 保留块总数*/unsigned short s_free_blocks_count; // 空闲块总数unsigned short s_free_inodes_count; /* 空闲的inode总数*/unsigned short s_log_block_size; /* block 的大小*/};/**账户信息**/struct user{unsigned short user_id; //用户IDunsigned short user_access; //权限string username; //用户名string password; //密码};/**文件/目录结构**/struct directory{string name; /*目录名*/unsigned short d_ino; /*目录号*/};三、所用仪器、材料(设备名称、型号、规格等)。

计算机一台四、实验方法、步骤#include<stdio.h>#include<stdlib.h>#include<string.h>#include<iostream.h>struct OpenFileTable //打开文件表数据结构{long offset; // 当前文件读写指针char file_name[10]; // 文件名数组long int file_start; // 文件起始块号long int file_length; // 文件长度(字节)};struct FCB_Block //FCB数据结构{int flag; // 标志,-1表示未用,1表示文件用char file_name[10]; // 文件名数组long int file_date; // 文件建立日期long int file_time; // 文件建立时间long int file_start; // 文件起始块号long int file_length; // 文件长度(字节)};struct Super_Block // 超级块数据结构, 文件系统的分区信息,存放在0#物理块中{unsigned long int fs_totalsize; // 整个分区的总磁盘物理块数unsigned long int fs_freesize; // 分区的所有空闲磁盘物理块数unsigned int fs_blocksize; // 文件系统的物理块大小(字节)unsigned int fs_fat_start; // FAT的起始磁盘物理块号unsigned int fs_fat_size; // FAT占用的磁盘物理块数unsigned int fs_dir_start; // 根目录的起始磁盘物理块号unsigned int fs_dir_size; // 根目录占用的磁盘物理块数unsigned int fs_data_start; // 数据区起始磁盘物理块号unsigned long int fs_data_size; // 数据区的磁盘物理块数};const char DiskName[]="FileSys.dat"; //磁盘文件名char rw_buffer[512]; // 读写使用的缓冲区struct FCB_Block filefcb[130]; // 读写目录使用的数据结构struct Super_Block FsSupBlk; // 读写超级块使用的数据结构long int fat_buffer[5000]; // 读写FAT使用的缓冲区,为简化在系统启动时全部装入内存,0为空闲struct OpenFileTable OFT[16]; // 打开文件表,当前只使用OFT[0]unsigned int block_size; // 物理块大小(字节)unsigned long int total_disk_size; // 磁盘总容量(物理块数)unsigned int total_dir_size; // 目录占有的物理块数unsigned int total_fat_size; // FAT占有的物理块数long int find_fcb; // 记录读FCB块的次数FILE *fsPtr; // 模拟磁盘的文件指针/*********************** 磁盘块的申请***********************************/unsigned long int Get_Block(unsigned long int count) //分配count个物理快,返回首块指针,其它已经连接{unsigned long int tmp,firstblk,tmpcount;unsigned long int i;int flag=1;if (count > FsSupBlk.fs_freesize){ printf(" ==== 没有足够磁盘容量,不能分配!==== \n"); return 0; }tmpcount=0;for(i=FsSupBlk.fs_data_start;i<=FsSupBlk.fs_totalsize;i++)//建立分配链{if(fat_buffer[i] == 0) //文件未占有,分配{if (flag==1){ firstblk=i; flag=-1;}else{ fat_buffer[tmp]=i; }tmp=i;fat_buffer[i]=-1;tmpcount++;if(tmpcount==count) //分配完成{ FsSupBlk.fs_freesize=FsSupBlk.fs_freesize-count;//减少可分配物理块return firstblk;}}}return -1; //分配不成功}/*********************** 磁盘块的回收***********************************/void Put_Block(unsigned long int addr){ unsigned long int i,j;int count;i=addr; count=0;while(fat_buffer[i]!=-1){j=fat_buffer[i]; //下一项fat_buffer[i] = 0;count++;i=j;}fat_buffer[i] = 0;FsSupBlk.fs_freesize=FsSupBlk.fs_freesize+count+1;//增加可分配物理块return;}/*********************** 读磁盘块***********************************/void Read_Block(unsigned long int addr,char *buf){if (addr>FsSupBlk.fs_totalsize){ printf(" ==== 超出磁盘容量,不能读!==== \n"); return; }fseek(fsPtr,FsSupBlk.fs_blocksize*addr,SEEK_SET);fread(buf,512,1,fsPtr);return;}/*********************** 写磁盘块***********************************/void Write_Block(unsigned long int addr,char *buf){if (addr>FsSupBlk.fs_totalsize){ printf(" ==== 超出磁盘容量,不能写!==== \n"); return; }fseek(fsPtr,FsSupBlk.fs_blocksize*addr,SEEK_SET);fwrite(buf,512,1,fsPtr);return;}/*********************** 格式化磁盘***********************************/void Real_Format(){unsigned long int bcount;long int fatval,i;char *c;//更改系统超级块信息FsSupBlk.fs_totalsize=total_disk_size;FsSupBlk.fs_blocksize=block_size;FsSupBlk.fs_dir_start=1;FsSupBlk.fs_dir_size=total_dir_size;FsSupBlk.fs_fat_start=total_dir_size+1;FsSupBlk.fs_fat_size=total_fat_size;FsSupBlk.fs_data_start=FsSupBlk.fs_fat_start+FsSupBlk.fs_fat_size;FsSupBlk.fs_data_size = FsSupBlk.fs_totalsize - FsSupBlk.fs_dir_size - FsSupBlk.fs_fat_size-1;FsSupBlk.fs_freesize= FsSupBlk.fs_data_size;//初始化目录for(i=0;i<128;i++) filefcb[i].flag=-1; //为-1表示FCB未使用fseek(fsPtr,512L,SEEK_SET);fwrite(&filefcb[0],sizeof(struct FCB_Block),128,fsPtr);//初始化FATfatval=FsSupBlk.fs_fat_start*512;fseek(fsPtr,fatval,SEEK_SET); //定位文件指针bcount=FsSupBlk.fs_fat_size+FsSupBlk.fs_dir_size+1;for(i=0;i<bcount;i++) fat_buffer[i]=-1; //标记已经使用的磁盘数据块,即FAT区、目录区和启动区for(;i<FsSupBlk.fs_totalsize;i++) fat_buffer[i]=0; //为0表示为空的物理快fwrite(&fat_buffer[0],sizeof(long int),FsSupBlk.fs_totalsize,fsPtr);//初始化数据区for(i=0;i<512;i++) rw_buffer[i]=' ';//缓冲区清空for(i=FsSupBlk.fs_data_start;i<FsSupBlk.fs_totalsize;i++) Write_Block(i,rw_buffer); //缓冲区写入第i块}/***********************新建系统磁盘文件***********************************/void Create_Disk(){long int i;unsigned long int total;fsPtr=fopen(DiskName,"wb+");if(fsPtr==NULL){printf(" 不能建立磁盘所需的文件!\n");exit(0);}// 建立磁盘文件total=total_disk_size;for(i=0;i<total;i++) //建立大小为total的磁盘文件fwrite(rw_buffer,512,1,fsPtr);fclose(fsPtr);fsPtr=fopen(DiskName,"rb+");Real_Format();return;}/***********************读写系统超级块信息***********************************/void Read_Boot() //读取磁盘超级块数据信息{rewind(fsPtr);fread(&FsSupBlk,sizeof(struct Super_Block),1,fsPtr);return;}void FileBoot() //超级块数据信息存盘{rewind(fsPtr);fwrite(&FsSupBlk,sizeof(struct Super_Block),1,fsPtr);return;}/***********************FAT操作***********************************/void LoadFat() //装载全部FAT到内存{fseek(fsPtr,FsSupBlk.fs_fat_start*512,SEEK_SET);fread(fat_buffer,sizeof(long int),FsSupBlk.fs_totalsize ,fsPtr);return;}void SaveFat() //FAT到文件FAT区{fseek(fsPtr,FsSupBlk.fs_fat_start*512,SEEK_SET);fwrite(fat_buffer,sizeof(long int),FsSupBlk.fs_totalsize,fsPtr);return;}/***********************显示超级块信息***********************************/ void boot_dis(){printf("FsSupBlk.fs_totalsize=%ld\n",FsSupBlk.fs_totalsize);printf("FsSupBlk.fs_blocksize=%d\n",FsSupBlk.fs_blocksize);printf("FsSupBlk.fs_dir_start=%d\n",FsSupBlk.fs_dir_start);printf("FsSupBlk.fs_dir_size=%d\n",FsSupBlk.fs_dir_size);printf("FsSupBlk.fs_fat_start=%d\n",FsSupBlk.fs_fat_start);printf("FsSupBlk.fs_fat_size=%d\n",FsSupBlk.fs_fat_size);printf("FsSupBlk.fs_data_start=%d\n",FsSupBlk.fs_data_start);printf("FsSupBlk.fs_data_size=%ld\n",FsSupBlk.fs_data_size);printf("FsSupBlk.fs_freesize=%ld\n",FsSupBlk.fs_freesize);}/***********************系统初始化***********************************/void Sys_Init() //初始化{fsPtr=fopen(DiskName,"rb+");if(fsPtr == NULL) Create_Disk();Read_Boot();//boot_dis();LoadFat();return;}/***********************显示操作***********************************/void dir() //显示目录下的文件{int i,countFile=0;char str[16];long int n,pos_dir,pos_fat;cout<<endl;pos_dir=FsSupBlk.fs_dir_start*512;pos_fat=FsSupBlk.fs_fat_start*512;fseek(fsPtr,pos_dir,SEEK_SET);while(ftell(fsPtr)<pos_fat){fread(&filefcb[0],sizeof(struct FCB_Block),16 ,fsPtr);for(i=0;i<16;i++)if(filefcb[i].flag == 1) //文件占有{countFile++;n = filefcb[i].file_length;printf(" %-15s<%s>%15d bytes\n", filefcb[i].file_name,"file",n);}}cout<<endl;printf(" 总共有%d 个文件\n",countFile);printf(" 系统总共有%ld 个物理块可用\n\n",FsSupBlk.fs_freesize);}/*************************查找文件*******************************/ //查找文件,文件存在返回当前FCB数组下标,否则返回-1int Find_File(char *filename){int i;long int pos_dir,pos_fat;pos_dir=FsSupBlk.fs_dir_start*512;pos_fat=FsSupBlk.fs_fat_start*512;find_fcb=0;fseek(fsPtr,pos_dir,SEEK_SET);while(ftell(fsPtr)<pos_fat){ find_fcb++;fread(&filefcb[0],sizeof(struct FCB_Block),16 ,fsPtr);for(i=0;i<16;i++)if(filefcb[i].flag!=-1){ if(strcmp(filename,filefcb[i].file_name) == 0) return i;} //文件存在}return -1;}/*************************创建文件*******************************/void create(char *fname,long int num) //在当前目录下创建一个名字为str的文件,长度为num{int i,j; //true表示没有与该名字重名的文件int tempnode;long int pos_dir,getnum=0;unsigned long int blkcount;blkcount= num/512+1; //计算需要的物理块if(FsSupBlk.fs_freesize < blkcount) //磁盘没有足够空间{printf("\n 磁盘没有足够空间,不能建立!\n\n");return;}tempnode=Find_File(fname);if (tempnode!=-1) //表示文件存在{ printf("\n 文件已经存在,不需要建立!\n\n"); return;} // 建立文件的处理pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize; fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区for(i=0; i<FsSupBlk.fs_dir_size; i++){//Read_Block(i+FsSupBlk.fs_dir_start,(char *)filefcb);fread(&filefcb[0],sizeof(struct FCB_Block),16 ,fsPtr);for(j=0;j<16;j++)if(filefcb[j].flag == -1) //找到空目录项{// 分配空间, 标记FCB数据项,并将FCB写磁盘getnum=Get_Block(blkcount);if(getnum==-1){ printf("不能分配存储空间\n");return;}filefcb[j].file_start=getnum;filefcb[j].flag = 1;filefcb[j].file_length=num;strcpy(filefcb[j].file_name,fname);//filefcb[].file_time=//filefcb[].file_date=// 改变磁盘FCB值pos_dir=pos_dir+sizeof(struct FCB_Block)*(i*16+j);fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区的FCB项fwrite(&filefcb[j],sizeof(struct FCB_Block),1 ,fsPtr);//Write_Block(i+FsSupBlk.fs_dir_start,(char *)filefcb);printf(" 文件占用了%d 个物理块\n",blkcount);printf(" 系统还有%ld 个物理块可用\n\n",FsSupBlk.fs_freesize);return;}}//没有FCB项,不能建立文件cout<<"当前没有足够的目录区,不能建立文件! "<<endl;return;}/*************************格式化*******************************/void format(){char ch;cout<<"\n 真希望格式化磁盘吗?(y/n) ";cin>>ch;if(ch=='y'||ch=='Y'){Real_Format();printf("\n Format Successful!\n\n");}}/****************************删除文件操作**************************************/void del(char *fname){long int tempnode;long int pos_dir;tempnode=Find_File(fname);if (tempnode==-1) //表示文件不存在{ printf("\n 文件不存在,不能删除!\n\n"); return;}// 删除文件的处理Put_Block(filefcb[tempnode].file_start); // 释放文件存储空间filefcb[tempnode].flag =-1; // 标记FCB项可用// 修改的FCB项写回磁盘pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize+((find_fcb-1)*16+tempnode)*siz eof(struct FCB_Block);fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区fwrite(&filefcb[tempnode],sizeof(struct FCB_Block),1 ,fsPtr);return;}/*************************写文件*******************************/void write(char *fname ,int num)//写文件,仅实现在文件尾部填加内容,并限制在512个字节内{int tempnode;int i,j,x;int rescount;long int pos_dir;if (num > 512){printf("\n 不能写大于512字节的数据!\n\n");return;}tempnode=Find_File(fname);if (tempnode==-1) //表示文件不存在{printf("\n 文件不存在,不能写!\n\n");return;}// 写文件的处理char *string=new char [num]; //申请空间for(i=0;i<num;i++){cin>>string[i];}rescount=filefcb[tempnode].file_length % FsSupBlk.fs_blocksize; if (num> FsSupBlk.fs_blocksize-rescount){if (FsSupBlk.fs_freesize<1){printf("\n 文件系统没有足够空间,不能写!\n\n");return;}}for(j=filefcb[tempnode].file_start;fat_buffer[j]!=-1;j=fat_buffer[j]); Read_Block(j,rw_buffer);if (num<= FsSupBlk.fs_blocksize-rescount){for(i=0;i<num;i++) rw_buffer[rescount+i]=string[i];Write_Block(j,rw_buffer);}else{for(i=0;i<FsSupBlk.fs_blocksize-rescount;i++)rw_buffer[rescount+i]=string[i];Write_Block(j,rw_buffer);fat_buffer[j]=Get_Block(1);j=fat_buffer[j];for(x=0;x<FsSupBlk.fs_blocksize;x++) rw_buffer[x]=' ';for(x=0;x<num-(FsSupBlk.fs_blocksize-rescount);x++) rw_buffer[x]=string[i+x];Write_Block(j,rw_buffer);}//delete []string;// 修改FCB项并写回磁盘filefcb[tempnode].file_length+=num; // 增加文件的长度pos_dir=FsSupBlk.fs_dir_start*FsSupBlk.fs_blocksize+((find_fcb-1)*16+tempnode)*siz eof(struct FCB_Block);fseek(fsPtr,pos_dir,SEEK_SET); //定位到目录区fwrite(&filefcb[tempnode],sizeof(struct FCB_Block),1 ,fsPtr);cin.ignore(10000,'\n'); //清除输入流缓冲区cout<<endl<<"=================== 写文件完成!=============="<<endl;return;}void copyFcbtoOft(int fcbpos){OFT[0].offset =0;strcpy(OFT[0].file_name,filefcb[fcbpos].file_name);OFT[0].file_start = filefcb[fcbpos].file_start ;OFT[0].file_length= filefcb[fcbpos].file_length ;}/*************************读文件*******************************/void read(char *fname,long start,int count)//读文件,限制在512个字节内{int tempnode;int stblknum,offset;int dspnum;long i,j,x;tempnode=Find_File(fname);if (tempnode==-1) //表示文件不存在{ printf("\n 文件不存在,不能读!\n\n");return; }if (start > filefcb[tempnode].file_length) //读的数据超出文件范围{ printf("\n 超出文件范围,不能读!\n\n");return; }// 读文件的处理printf("\n========================================\n"); stblknum=start/FsSupBlk.fs_blocksize+1; // 起始物理块offset=start%FsSupBlk.fs_blocksize; // 起始物理块的偏移量if(start+count>filefcb[tempnode].file_length )count= filefcb[tempnode].file_length-start;for(i=filefcb[tempnode].file_start,j=1;j<stblknum;j++)i=fat_buffer[i];Read_Block(i,rw_buffer);if(start+count>filefcb[tempnode].file_length )count= filefcb[tempnode].file_length-start;if(count<=FsSupBlk.fs_blocksize-offset){for(j=0;j<count;j++) cout<<rw_buffer[j+offset];}else{for(j=0;j<FsSupBlk.fs_blocksize-offset;j++) cout<<rw_buffer[j+offset];dspnum=(count-(FsSupBlk.fs_blocksize-offset))/FsSupBlk.fs_blocksize+1;for(j=0;j<dspnum-1;j++){i=fat_buffer[i];Read_Block(i,rw_buffer);for(x=0;x<FsSupBlk.fs_blocksize;x++)cout<<rw_buffer[x];}i=fat_buffer[i];Read_Block(i,rw_buffer);x=(count-(FsSupBlk.fs_blocksize-offset))%FsSupBlk.fs_blocksize;for(j=0;j<x;j++) cout<<rw_buffer[x];}cout<<endl<<"============= 读文件完成!================"<<endl;return;}/*************************显示帮助*******************************/void display_help(){printf(" 写文件wf filename size \n");printf(" 读文件rf filename start size \n");printf(" 删除文件df filename \n");printf(" 建立文件cf filename size \n");printf(" 显示文件dir \n");printf(" 磁盘格式化format \n");printf(" 退出文件系统quit \n\n");}/*************************命令解释*******************************/void CmdShell() //全部命令的解释执行过程{int j;int parameter; // 记录命令行参数个数int len; // 输入的命令行长度char string[50]; // 输入的命令行字符串char *str[4]; // 分解出的命令行参数bool flag; // 标志cout<<"\n 输入help查看所有命令"<<endl<<endl;while(1){printf("c:\>"); //输出系统提示符gets(string);len = strlen(string);//命令行信息的解析过程for(parameter = 0, flag = true, j = 0; j<len ; j++){if(string[j] == ' ') //读到输入字符为空格时,输出回车{ flag = true; string[j] = '\0'; }elseif(flag){ flag = false;str[parameter++] = &string[j]; //分解出的命令,以空格为各参数的分割符} //第一个为操作命令,其他为参数}strlwr(str[0]);// 根据操作命令执行不同的过程if(!strcmp("cf",str[0])) // 创建文件{if(parameter != 3)printf(" 格式不正确,请重新输入!\n ");elsecreate(str[1],atol(str[2])); } // 创建一个名字为str[0]大小为str[2]的文件else if(!strcmp("df",str[0])) // 删除文件{ if(parameter != 2)printf(" 格式不正确,请重新输入!\n ");else//disfat();}del(str[1]); } //删除文件str[1]else if(!strcmp("dir",str[0])) //显示文件命令dir();else if(!strcmp("help",str[0]))display_help();else if(!strcmp("format",str[0]))format();else if(!strcmp("wf",str[0])) //写文件{ if(parameter != 3)printf(" 格式不正确,请重新输入!\n ");elsewrite(str[1],atol(str[2])); }else if(!strcmp("rf",str[0])) //读文件内容{ if(parameter != 4)printf(" 格式不正确,请重新输入!\n");elseread(str[1],atol(str[2]),atol(str[3])); }else if(!strcmp("quit",str[0])) //退出{ SaveFat(); fclose(fsPtr); exit(0);}elseif (parameter >0 ) cout<<"命令错误!"<<endl;}}/************************* 主过程*******************************/void main(){block_size=512; // 物理块大小512字节total_disk_size=4096; // 磁盘总容量为4096块total_dir_size=16; // 目录占有的物理块数为16块total_fat_size=32; // FAT占有的物理块数为32块Sys_Init(); //初始化磁盘系统CmdShell(); //命令解释过程}五、实验过程原始记录(数据、图表、计算等)六、实验结果、分析和结论(误差分析与数据处理、成果总结等。

相关主题