实验三文件管理一、实验目的理解文件系统的主要概念及文件系统内部功能和实现过程。
二、实验内容采用二级文件目录结构,编写程序实现文件系统的文件存储空间的管理、文件的物理结构、目录结构管理和文件操作。
具体如下:1、设计一个有m个用户的文件系统,每个用户最少可保存一个文件。
2、规定用户在一次运行中只能打开K个文件。
3、系统能检查键入命令的正确性,出错时应能显示出错原因。
4、对文件应能设置保护措施,如只能执行、允许读、允许写等。
5、对文件的操作设计提供一套文件操作:CREATE建立文件;DELETE删除文件;OPEN打开文件;CLOSE关闭文件;READ读文件;WRITE写文件。
三、实验要求①详细描述实验设计细想、程序结构及各模块设计思路。
②详细描述程序所用数据结构及算法③给出测试用例及实验结构④为增加程序可读性,在程序中进行适当注释说明⑤认真进行实验总结,包括:设计中遇到的问题、解决方法和收获⑥实验报告撰写要求结构清晰、描述准确逻辑性强四、实验过程举例:主文件目录mfd=recordusername :string[maxlen];files :array[1..K] of ufd;ofiles :arrau[1..S] of uodend;用户打开文件目录表:uod=recordfilename:string[maxlen];attrib:attrib;status:(open,create);rp,up:integer;end;用户文件目录:ufd=recordfielname:string[maxlen];attrib ro,rw);len:integer;addr:integer;end;流程图:二、主要数据结构界面采用VC6 MFC环境开发#define MAXUSER 10 //假想文件系统最多支持的人数#define BLOCKSIZE 32 //虚拟磁盘中物理块为每块32字节#define DISKSIZE BLOCKSIZE*1000 //虚拟磁盘容量为1000*32=32Kstruct UFD //说明文件项的结构数组{char FileName[15];char Time[16]; //文件建立或修改时间如2003/5/6 12:00bool IsExist; //文件是否存在,删除时标为0bool IsShared; //共享标记,共享文件可被其它用户所访问bool AttrRead; //文件是否可读bool AttrWrite; //文件是否可写bool AttrExecute; //文件是否可执行HTREEITEM treeNode; //用于树控件显示的结点句柄USHORT FileLen; //文件占用字节数USHORT BlockNum; //文件占用的物理块数USHORT FileLink[100];//文件物理块地址数组,每块32字节,限定一个文件最大100*32=3200字节};struct MFD{char UserName[10]; //主目录用户名bool IsExist; //该用户否存在UFD ufd[MAXFILE]; //用户文件数组USHORT nItem;//UFD个数};struct HEADBLOCK{BYTE pStack; //堆栈指针SHORT pBlock[10]; //块号 pBlock[10]是下一个盘块号逻辑地址};struct BLOCK //虚拟磁盘的物理块数据结构{union{BYTE block[32]; //一块为32字节HEADBLOCK HeadInfo;};};struct FAT{BLOCK SuperBlock; //超级块,指示第一个空闲块逻辑号USHORT MaxOpen; //该用户同时可打开的最大文件数USHORT UserNum; //最户数MFD Mfd[MAXUSER]; //最多可支持10个用户};//空闲块成组链接法bool OpenList[MAXUSER][MAXFILE]; //描述文件是否打开的布尔型数组FAT FileFAT; //描述文件记录项的FAT结构CFile FATIO; //负责和VDISK.DAT打交道的文件句柄CString CurrentUser; //当前登录的用户名说明:本实验采用模拟文件结构的方法,把记录用户帐号,用户文件和磁盘块的信息用当前目录下的VDISK.DAT来记录,可以把VDISK.DAT看成是一个虚拟的磁盘,其头部是FAT结构,用来记录各个用户和文件信息,紧接着是空闲块成组链接法的数据结构,每块32字节,每组10块,共1000块,也就是说,用户文件数据的总容量是32*1000字节,如果程序当前目录下找不到用于做实验用的VDISK.DAT,在登录时程序会提示是否“格式化虚拟磁盘”也就是新建一个VDISK.DAT文件,接着,程序会显示“用户管理”的窗口,此时应新建几个帐号用于登录做实验。
登录后,程序会显示该用户的所有文件,右方的文件列表会显示每个文件的属性信息,和WINDOWS的“资源管理器”相似。
用鼠标双击列表的每个文件就可以查看文件的内容。
单击“新建文件”按钮可以创建一个新的用户文件。
选中某个文件后,就可以进行相应的操作,如“修改文件”、“删除文件”或是“打开文件”,删除某个文件时检查该文件的属性,如果是只读的,就是显示警告窗口让用户确认是否一定要删除。
硬盘工具可以用图形方式显示“磁盘”块的详细情况,空白块说明该块没有使用,暗红色的说明块已分配,窗口还统计占用的空间大小、用户数等信息。
程序中用到的结构图如下图所示:MFD三、主要算法与部分代码void CDlgUser::OnAddUser(){UpdateData(true);if (erNum>=10){AfxMessageBox("用户数量已达到最大10个,你可以删除一些无用的帐号!");return;}for(int i=0;i<10;i++){if(FileFAT.Mfd[i].IsExist==false){wsprintf(FileFAT.Mfd[i].UserName,m_UserName);FileFAT.Mfd[i].IsExist=true;FileFAT.Mfd[i].nItem=0;break;}erNum++;WriteFAT();ReadFAT();ShowUser();//显示现有的用户列表m_UserName.Empty();UpdateData(false);}bool ReadBlock(int id, BLOCK* buffer) //读指定块号内容(32字节)到buffer所指向的单元{if(!FATIO) return false; //如果虚拟磁盘文件句柄为空,出错返回if(!FATIO.Seek(sizeof(FAT)+(id-1)*BLOCKSIZE,CFile::begin)) return false;//移动文件指针到指定块号if(FATIO.Read(buffer,BLOCKSIZE)!=BLOCKSIZE) return false;//读该块的内容到buffer指定的单元return true;}bool WriteBlock(int id, BLOCK* buffer) //把buffer所指向的单元的内容(32字节)写到指定的物理块中{if(!FATIO) return false;if(!FATIO.Seek(sizeof(FAT)+(id-1)*BLOCKSIZE,CFile::begin)) return false;FATIO.Write(buffer,BLOCKSIZE);return true;}USHORT AllocBlock() //分配一物理块,成功返回逻辑块号,失败返回0;{if(!FileFAT.SuperBlock.HeadInfo.pBlock[FileFAT.SuperBlock.HeadInfo.pStack]) return 0;//没有空间可分配,失败返回if(FileFAT.SuperBlock.HeadInfo.pStack<9)//如果一组的空闲块没有分配完{WriteFAT();//将返回超级块所指的空闲块,再将堆栈指针加一return FileFAT.SuperBlock.HeadInfo.pBlock[FileFAT.SuperBlock.HeadInfo.pStack++];}else //如果分配的空闲块是组头{WriteFAT();USHORT returnBlock=FileFAT.SuperBlock.HeadInfo.pBlock[9];//将要分配的组头复制到超级块,再返回组头作为空闲块if(!ReadBlock(returnBlock,&FileFAT.SuperBlock)) return 0;return returnBlock;}WriteFAT();return 0;}bool FreeBlock(USHORT BlockID) //回收一物理块,成功返回TRUE,失败返回FALSE{if(FileFAT.SuperBlock.HeadInfo.pStack>0)//如果该组的空闲没有回收满{//堆栈指针退一,把回收的块号记入超级块FileFAT.SuperBlock.HeadInfo.pBlock[--FileFAT.SuperBlock.HeadInfo.pStack]=BlockID;BLOCK newBlock;if (!WriteBlock(BlockID,&newBlock)) return false;}else//如果该组已回收满,需要加入一新组的话{if (!WriteBlock(BlockID,&FileFAT.SuperBlock)) return false;//将超级块的栈内容复制到要回收的块中 FileFAT.SuperBlock.HeadInfo.pStack=9;//将超级块的栈指针指向回收的块FileFAT.SuperBlock.HeadInfo.pBlock[9]=BlockID;}WriteFAT();return true;}bool ReadFAT() //从虚拟磁盘中读取FAT结构信息到FileFAT中{ZeroMemory(&FileFAT,sizeof(FileFAT));FATIO.SeekToBegin();if (!FATIO.Read(&FileFAT,sizeof(FileFAT))) return false;return true;}bool Format()//格式化虚拟磁盘,创建VDISK.DAT,所有用户和文件信息将被清空!{CString FATFile;int i;char fname[128];GetCurrentDirectory(128,fname); //FAT表信息保存在当前目录的VDISK.DAT中FATFile.Format("%s",fname);if (FATFile.Right(1)!="\\")FATFile+="\\VDISK.DAT";elseFATFile+="VDISK.DAT";CFile fout;if( !fout.Open(FATFile,CFile::modeCreate|CFile::modeWrite,NULL))return false;ZeroMemory(&FileFAT,sizeof(FileFAT));FileFAT.SuperBlock.HeadInfo.pStack=0;for(i=0;i<10;i++){FileFAT.SuperBlock.HeadInfo.pBlock[i]=i+1;}fout.WriteHuge(&FileFAT,sizeof(FileFAT));BYTE *Buffer;Buffer=(BYTE*)malloc(DISKSIZE);//申请成组链接法所需的磁盘块空间ZeroMemory(Buffer,DISKSIZE);BLOCK newBlock;for (i=10;i<=990;i+=10){ZeroMemory(&newBlock,sizeof(newBlock));newBlock.HeadInfo.pStack=0;for (int k=0;k<10;k++)memcpy(Buffer+32*(i-1),&newBlock,32);}fout.WriteHuge(Buffer,DISKSIZE); //将格式化的块信息写入VDISK.DATfree(Buffer);fout.Close();AfxMessageBox("创建虚拟磁盘文件成功!请选择用户管理添加新用户。