基于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
**/

结语

这个文件模拟系统基本实现了多叉树的初始化以及节点的新建,删除等常见操作,对于删除操作我实现的不是很好,没有实现递归删除,这会导致很大的内存泄露。大家可以根据此代码进行相应的修改。

希望此代码能给大家带来收获,谢谢大家!

坚持不懈地努力才能成为大神!

posted @ 2021-02-02 22:27  己平事  阅读(3773)  评论(0编辑  收藏  举报