一.设计说明设计实现一个简单的模拟文件管理系统,包括目录文件、普通文件、i结点和存储区,具体要求如下:(1)程序初始化时应构造如图1-1所示的目录结构。
图1-1 初始目录树(2)在此模拟文件管理系统中可以实现的操作有:改变目录:cd<目录名>,工作目录转移到指定的目录下。
目录不存在时,给出错误信息。
创建文件:edit<文件名>,创建一个指定名字的新文件,即在目录中增加一项,不考虑文件的内容。
对于重名文件给出错误信息。
删除文件:del<文件名>,当没在用户使用指定文件时,将其删除。
文件不存在时给出错误信息。
显示目录:dir<目录名>,显示指定目录下的全部文件和第一级子目录,如果没有指定目录名,则显示当前目录下的相应内容。
创建目录:md<目录名>,在指定路径下创建指定的目录,如没有指定路径,则在当前目录下创建指定的目录。
对于重名目录给出错误信息。
删除目录:rd<目录名>,删除指定目录及其下的全部文件和子目录。
如果指定目录为空,可直接删除,否则给出用户提示是否删除。
其他说明:<目录名>和<文件名>都支持全路径名和相对路径名。
文件名由目录结构中各级文件名分量排列构成,各分量间用“/”隔开。
输入exit命令可退出此模拟文件管理系统。
二.工作原理2.1 编译工具本程序使用的函数均为标准C库函数,可以由任何支持标准C的编译器编译运行。
已经通过测试的编译环境如下:Windows平台:Visual C++ 6.0使用方法:用VC6打开fileSys.c文件,执行Build,根据对话框提示创建工程文件。
Build完成即可用Execute运行程序。
Linux平台: Gcc 2.96使用方法:到fileSys.c所在路径下,执行命令gcc-o fileSys fileSys.c生成可执行文件fileSys,执行./fileSys运行程序。
2.2 相关说明支持相对路径和绝对路径:相对路径如“cd user/file1↙”,“dir↙”绝对路径如“cd /user/file1”(root指根目录)、“cd /user/file1↙”、“cd/↙”(表示对根目录操作)如果命令或路径出错会有详尽的提示。
在新建文件或目录中,若文件名或目录名同名的文件或目录下已存在,则创建失败并给以提示。
CD命令中,如果遇到路径错误,将报错,并保持在当前路径下等待下一次命令。
如果有命令格式或者文件目录格式有错,系统将报错,并提示用户,允许重试。
不允许对文件操作的命令与对目录操作的命令混用,否则报错。
本系统采用了动态分布存储空间的链表结构,所以对文件数目没有明确限制,只受系统资源制约。
Exit为退出系统命令,该命令不能接目录名。
在6个命令中,只有dir可接空路径名,表示对当前目录的操作,其他的将会对命令格式的错误情况报错。
三.详细设计3.1程序框架及函数调用关系函数之间的关系如图3-1所示,每个函数的说明如下:Main(): 主函数CdComd(): 改变目录功能处理EditComd(): 创建文件功能处理DelComd(): 删除文件功能处理RdComd(): 删除目录功能处理Dircomd(): 显示目录功能处理Mdcomd(): 创建目录功能处理Init(): 初始化文件树ParseCommand(): 接受输入的命令并将其分解成操作名和路径文件名ExecuteCommand(): 执行命令,根据参数Paral,调用相应的功能处理模块;若输入命令有误,则报错图3-1 调用关系图FindPath(): 查找参数ph所指向的路径FindFileName(): 从参数para2中找到要建立或删除的子目录,文件名,并调用查找路径子函数把指针指向其父亲结点CreateFileNode(): 创建结点GetInput(): 缓冲区安全输入子函数,如果输入超过缓冲区长度,则截取前[缓冲区长度-1]位,最后一位补“/0”CheckCommand(): 命令检查GetDir(): 获取当前目录名Trim(): 对命令进行格式处理,即去掉空格等3.2数据结构及相应算法整个文件系统采用二叉树型存储结构,如图3-2所示图3-2 初始目录树每一个结点的结构如下:Struct FileNode{Char filename[FILENAME_LEN]; //文件名/目录名int isdir; //目录文件识别标志int i_nlind; //文件的链接数int adr; //文件的地址Struct FileNode *parent,*child; //指向父亲的指针和指向左孩子的指针Struct FileNode *sibling_prev,*sibling_next;//指向前一个兄弟的指针//和指向后一个兄弟的指针};3.3程序流程图本程序中共包含一个主函数和16个子函数,这里仅对其中的9个函数用流程图来进行详细说明。
(1) Main()主函数(见图3-3)图3-3 主程序流程图(2)FindFileName()子函数:获取文件或目录名,并调用查找路径子函数把指针指向其父亲结点(见图3-4)图3-4 FindFileName()(3)ParseCommand()分解命令子函数(见图3-5)图3-5 ParseCommand()(4)FindPath():查找路径子函数,ph是路径名参数(见图3-6)图3-6 FindPath()(5)CdComd():cd改变目录功能处理子函数(见图3-7)图3-7 CdComd()(6)EditComd():edit创建文件功能处理子函数(见图3-8)图3-8 EditComd()(7)DelComd():del删除文件功能处理子函数(见图3-9)图3-9 DelComd()(8)RdComd():rd删除目录功能处理子函数(见图3-10)图3-10 RdComd()(9)DirComd():dir显示目录功能处理子函数(见图3-11)图3-11 DirComd()3.4程序源代码#include <stdio.h>#include <iostream.h>#include <string.h>#include <ctype.h>#include <stdlib.h>#define FILENAME_LEN 21#define INPUT_LEN 81#define COMMAND_LEN 11//结点结构struct FileNode{char filename[FILENAME_LEN];//文件名/目录名int isdir;//目录文件识别标志int i_nlink;//文件的链接数int adr;//文件的地址struct FileNode *parent, *child;//指向父亲的指针和指向左孩子的指针struct FileNode *sibling_prev, *sibling_next;//指向前一个兄弟的指针和指向//后一个兄弟的指针.};void Init();//初始化文件树int ParseCommand();//接受输入的命令并把其分解成操作名和路径文件名void ExecuteCommand();//执行命令int cdComd();//处理cd命令int editComd();//处理edit命令int delComd();//处理del命令int rdComd();//处理rd命令int dirComd();//处理dir命令int mdComd();//处理md命令int FindPath(char *ph);//寻找参数ph所指向的路径//从参数Para2中找到要建立或删除的文件、目录名,并把指针指向其父亲结点int FindFilename(char Para2[]);struct FileNode* CreateFileNode(char filename[],int isdir,int i_nlink);//创建结点int GetInput(char* buffer,unsigned int buffer_len);//获取输入int CheckCommand();//命令检查int GetDir(int begin,char* path,char* curDir);//获取路径void Trim(char* str);struct FileNode *cp, *tp, *root,*upper;char path[INPUT_LEN-COMMAND_LEN];//记录当前走过的路径char curpath[INPUT_LEN-COMMAND_LEN],Para1[COMMAND_LEN],Para2[INPUT_LEN-COMMAND_LEN],tmppath[INPUT_LEN-COMMAND_LEN];char filename[FILENAME_LEN],dirname[FILENAME_LEN],tmp;unsigned int i,j;//主函数int main(){Init();//初始化文件树while(1){if(ParseCommand())//分解命令ExecuteCommand();//执行命令}}//执行命令子函数void ExecuteCommand(){int sign;//根据参数Para1调用相应的功能处理模块if(strcmp(Para1,"cd")==0)sign=cdComd(); //cd命令else if(strcmp(Para1,"edit")==0)sign=editComd(); //edit命令else if(strcmp(Para1,"del")==0)sign=delComd(); //del命令else if(strcmp(Para1,"dir")==0)sign=dirComd(); //dir命令else if(strcmp(Para1,"md")==0)sign=mdComd(); //md命令else if(strcmp(Para1,"rd")==0)sign=rdComd(); //rd命令else if(strcmp(Para1,"exit")==0)exit(0); //exit命令elseprintf("命令错误,请重试\n"); //命令输入不正确,报错}//创建结点struct FileNode* CreateFileNode(char filename[],int isdir,int i_nlink){//申请结点空间struct FileNode* node=(struct FileNode*)malloc(sizeof(struct FileNode));//相应内容赋初值strcpy(node->filename,filename);node->isdir=isdir;node->i_nlink=i_nlink;node->parent=NULL;node->child=NULL;node->sibling_prev=NULL;node->sibling_next=NULL;return node;}//初始化文件树void Init(){struct FileNode *binNode,*usrNode,*unixNode,*etcNode,*libNode,*userNode,*binNode2,*liuNode,*sunNode,*ftiNode;strcpy(path,"/"); //根目录写入当前路径//创建文件树的结点binNode=CreateFileNode("bin",1,0);usrNode=CreateFileNode("usr",1,0);unixNode=CreateFileNode("unix",0,0);etcNode=CreateFileNode("etc",1,0);libNode=CreateFileNode("lib",1,0); userNode=CreateFileNode("user",1,0); binNode2=CreateFileNode("bin",1,0);liuNode=CreateFileNode("liu",1,0); sunNode=CreateFileNode("sun",1,0);ftiNode=CreateFileNode("fti",1,0);cp=tp=root=CreateFileNode("/",1,0);//结点相应内容赋值root->parent=NULL;root->child=binNode;root->sibling_prev=root->sibling_next=NULL;binNode->parent=root;binNode->child=NULL;binNode->sibling_prev=NULL;binNode->sibling_next=usrNode;usrNode->parent=NULL;usrNode->child=libNode;usrNode->sibling_prev=binNode;usrNode->sibling_next=unixNode;unixNode->parent=NULL;unixNode->child=NULL;unixNode->sibling_prev=usrNode;unixNode->sibling_next=etcNode;etcNode->parent=NULL;etcNode->child=NULL;etcNode->sibling_prev=unixNode;etcNode->sibling_next=NULL;libNode->parent=usrNode;libNode->child=liuNode;libNode->sibling_prev=NULL;libNode->sibling_next=userNode;userNode->parent=NULL;userNode->child=NULL;userNode->sibling_prev=libNode;userNode->sibling_next=binNode2;binNode2->parent=NULL;binNode2->child=NULL;binNode2->sibling_prev=userNode;binNode2->sibling_next=NULL;liuNode->parent=libNode;liuNode->child=NULL;liuNode->sibling_prev=NULL;liuNode->sibling_next=sunNode;sunNode->parent=NULL;sunNode->child=NULL;sunNode->sibling_prev=liuNode;sunNode->sibling_next=ftiNode;ftiNode->parent=NULL;ftiNode->child=NULL;ftiNode->sibling_prev=sunNode;ftiNode->sibling_next=NULL;}//获取文件或目录名,并把指针指向其父亲结点int FindFilename(char Para2[]){i=strlen(Para2)-1;j=0;while(Para2[i]!='/'&& i>=0){filename[j]=Para2[i];i--; j++;}filename[j]='\0';//获得逆序的文件或目录名,存入filename中if(i<0) Para2[i+1]='\0';else Para2[i]='\0';j--;//filename逆转,获得正确的文件或目录名for(i=0;i<strlen(filename)/2;i++,j--){tmp=filename[i];filename[i]=filename[j];filename[j]=tmp;}//查找路径if(strlen(Para2)>0){int sign=FindPath(Para2);if(sign==0) return 0;}return 1;}//缓冲区安全输入子函数//如果输入超过buffer_len,则截取前buffer_len-1长度的输入,//buffer_len处字符用'/0'代替int GetInput(char* buffer,unsigned int buffer_len){unsigned int count=0;while(count<buffer_len){if((buffer[count]=getchar())==10){buffer[count]='\0';return count;}count++;}while(getchar()!=10);buffer[buffer_len-1]='\0';return -1;}//分解命令子函数int ParseCommand(){char Inputs[INPUT_LEN];int i=0,j=0,ch;unsigned int k=0;printf("%s>",path);//获取输入if(GetInput(Inputs,INPUT_LEN)==-1){printf("输入行太长。