基于C语言的文件管理模拟系统
基于C语言的文件管理模拟系统
前言
这是某大学的一个C语言课程设计题目,之前帮别人写过。程序写的并不是很完善,当时忙于交差,实际上存在很多漏洞,比如开辟的空间没有完全释放等等。其余的一些遗留的bug以及漏洞等等请大家多多指正,谢谢!
题目要求
编写程序,模拟命令行的常用文件系统管理命令,具体要求如下:
① 根路径为ROOT。首次进入模拟器时,提示符为“ROOT>",“>”左侧为当前路径,可在“>”后输入下述各命令。② 切换到当前路径下的某文件夹: cd文件夹。 如“cd music", 若当前路径下存在music文件夹,则提示符变为“当前路径\music>”,若不存在,则提示。
③ 切换到当前路径的上级文件夹: cd ...
④ 在任意路径下切换回根路径ROOT: cd \。
⑤ 列出当前路径下的全部文件夹和文件: dir。
⑥ 在当前路径下新建文件夹: md文件夹 名称。
⑦ 在当前路径下新建文件: mf文件名称。
⑧ 删除当前路径下的某文件或文件夹(及其下所有文件夹及文件): del文件或文件夹名称。
注意:
① 以上各命令涉及到的文件夹和文件,仅在内存中用树结构模拟,而非真正的文件系统。
② 树中结点要包含必要的信息,如:文件或文件夹名称、区分文件或文件夹的标识、文件创建日期等。
设计思路
要实现此系统,涉及到的算法及知识包括:树的创建、遍历、查找、插入、删除。
以ROOT作为根节点,自上到下用多叉树结构实现一个文件系统,每个节点代表一个文件或者文件夹(以标志位区分)。通过cd命令进入当前树节点的子节点,cd ..返回上层目录(文件节点中包含一个pNode指针位,表示当前节点的父节点,用以实现返回功能,这有点类似于树的双亲表示法)。
具体的实现思路和方法我已经详细注释到代码中。
具体实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define FILEMAXN 100
#define OPMAXN 100
#define NAMEMAXN 100
#define PATHMAXN 1000
typedef struct FileNode{
char name[NAMEMAXN]; //文件名或者文件夹名
char path[PATHMAXN]; //文件(夹)路径
int flag; //区分文件或者文件夹的标识->0: 文件夹,1: 文件
char datetime[20]; //文件创建日期
int filenumber; //文件夹包含的文件(夹)数量
struct FileNode** files; //文件夹包含的文件(夹)列表
struct FileNode* pNode; //上级目录
}FileNode, *FileTree;
//日期函数,用于记录文件创建日期
//本函数可以不用看,下面的一些函数比较重要
char* getDateTime(){
char cur_time[20];
time_t t;
struct tm * lt;
time(&t);
lt = localtime(&t); //转为时间结构
sprintf(cur_time, "%04d/%02d/%02d %02d:%02d:%02d",lt->tm_year+1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
return cur_time;
}
//初始化文件系统,即建立一个根目录ROOT节点
FileTree init(){
FileTree root;
root = (FileNode *)malloc(sizeof(FileNode)); //分配空间
strcpy(root->name, "ROOT"); //字符串拷贝函数
strcpy(root->path, "ROOT");
root->flag = 0; //ROOT为目录节点,标识为0
root->filenumber = 0; //初始时所含子文件(夹)数量为0
root->files = NULL;
root->pNode = NULL;
return root;
}
//md:新建文件夹
void makeDirectory(FileNode *pNode, char dirname[]){
if(pNode->files == NULL){ //首次使用要分配空间
pNode->files = (FileNode**)malloc(FILEMAXN * sizeof(FileNode*));
}
pNode->files[pNode->filenumber] = (FileNode *)malloc(sizeof(FileNode));
FileNode *dir = pNode->files[pNode->filenumber++];
dir->flag = 0; //目录节点,标识为0
strcpy(dir->name, dirname);
dir->filenumber = 0;
dir->files = NULL;
dir->pNode = pNode;
//以下代码生成当前路径
char tmp[PATHMAXN];
strcpy(tmp, pNode->path);
strcat(tmp, "\\");
strcat(tmp, dirname);
strcpy(dir->path, tmp);
}
//mf:新建文件
void makeFile(FileNode *pNode, char filename[]){
if(pNode->files == NULL){
pNode->files = (FileNode**)malloc(FILEMAXN * sizeof(FileNode*));
}
pNode->files[pNode->filenumber] = (FileNode *)malloc(sizeof(FileNode));
FileNode *dir = pNode->files[pNode->filenumber++];
dir->flag = 1; //文件节点,标识为1
strcpy(dir->name, filename);
dir->filenumber = 0;
dir->files = NULL;
dir->pNode = pNode;
}
//dir:列出当前目录下全部文件(夹)
void showDir(FileNode *pNode){
int i;
//遍历打印文件名
for(i = 0; i < pNode->filenumber; i++){
printf("%s ", pNode->files[i]->name);
}
printf("\n");
}
//cd:切换到当前路径下的某个文件夹
FileNode* enterSubDir(FileNode *pNode, char dirname[]){
FileNode* curNode = NULL;
int i;
for(i = 0; i < pNode->filenumber; i++){
if(strcmp(pNode->files[i]->name, dirname) == 0
&& pNode->files[i]->flag == 0){
//若有此文件夹,则将当前节点切换为此文件夹
curNode = pNode->files[i];
}
}
return curNode;
}
//del:删除文件(夹)
int delFile(FileNode *pNode, char dirname[]){
int i;
for(i = 0; i < pNode->filenumber; i++){
if(strcmp(pNode->files[i]->name, dirname) == 0){
free(pNode->files[i]); //释放空间
int j = i;
for(; j < pNode->filenumber - 1; j++){
pNode->files[j] = pNode->files[j + 1]; //后面节点前移
}
pNode->filenumber --; //子文件(夹)数量减一
}
}
}
void showInfo()
{
printf(" ******************************************************\n\n");
printf(" * 欢迎使用文件模拟系统 *\n \n");
printf(" ******************************************************\n\n");
printf(" 该系统目前支持如下功能:\n");
printf(" 1.切换到当前路径下的某文件夹: cd + 文件夹\n");
printf(" 2.切换到当前路径的上级文件夹: cd ..\n");
printf(" 3.在任意路径下切换回根路径ROOT: cd \\ \n");
printf(" 4.列出当前路径下的全部文件夹和文件: dir\n");
printf(" 5.在当前路径下新建文件夹: md + 文件夹名\n");
printf(" 6.在当前路径下新建文件: mf + 文件名\n");
printf(" 7.删除当前路径下的某文件(夹)名: del文件(夹)名\n");
printf(" ******************************************************\n");
}
//主函数
int main()
{
showInfo();
FileTree rootDir = init(); //初始化文件系统,
FileNode *curDir = rootDir; //切换当前节点为根节点
char curPath[PATHMAXN] = "ROOT"; //切换当前路径为根路径
printf("%s> ", curPath); //输出 ROOT>
char operation[OPMAXN];
while(gets(operation)!= EOF){ //获取输入
char *op = strtok(operation, " ");
char *arg = strtok(NULL, " "); //以上分割出操作命令和参数,比如cd music,则命令为cd,参数为music
if(strcmp(op, "md") == 0){ //md
makeDirectory(curDir, arg);
}else if(strcmp(op, "mf") == 0){ //mf
makeFile(curDir, arg);
}else if(strcmp(op, "del") == 0){ //del
delFile(curDir, arg);
}else if(strcmp(op, "dir") == 0){ //dir
showDir(curDir);
}else if(strcmp(op, "cd") == 0){ //cd
if(strcmp(arg, "..") == 0){ //cd ..
curDir = curDir->pNode;
}else if(strcmp(arg, "\\") == 0){ //cd \ ---切换为根目录
curDir = rootDir;
}else{ //cd music --进入子目录
FileNode *pNode = curDir;
curDir = enterSubDir(curDir, arg);
if(!curDir){ //出现未知目录名,报错
printf("ERROR:\"%s\"目录下没有\"%s\", 请重新输入!\n",pNode->name, arg);
curDir = pNode;
printf("%s> ", curPath);
continue;
}
}
strcpy(curPath, curDir->path);
}else if(strcmp(op, "exit") == 0){ //exit 退出
printf("已退出系统, 谢谢使用!\n", op);
break;
}else{ // 出现未知命令,报错
printf("ERROR:不支持\"%s\"命令, 请重新输入!\n", op);
}
printf("%s> ", curPath);
}
return 0;
}
//测试用例如下,可直接复制执行
//当然自己构造也可以
/*
md music
md video
mf file1.txt
mf file1.txt
dir
del file1.txt
dir
cd music
mf a.mp3
mf b.mp3
dir
cd ..
cd video
mf c.mp4
mf d.mp4
dir
cd \
cd music
dir
del a.mp3
dir
exit
**/
结语
这个文件模拟系统基本实现了多叉树的初始化以及节点的新建,删除等常见操作,对于删除操作我实现的不是很好,没有实现递归删除,这会导致很大的内存泄露。大家可以根据此代码进行相应的修改。
希望此代码能给大家带来收获,谢谢大家!
坚持不懈地努力才能成为大神!