基於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
**/
結語
這個文件模擬系統基本實現了多叉樹的初始化以及節點的新建,刪除等常見操作,對於刪除操作我實現的不是很好,沒有實現遞歸刪除,這會導致很大的內存泄露。大家可以根據此代碼進行相應的修改。
希望此代碼能給大家帶來收獲,謝謝大家!
堅持不懈地努力才能成為大神!