#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#define MAX_NameLength 20//文件名最长长度
#define MAX_ContentLength 200//文件内容最长长度
#define MAX_RouteLength 20//文件路径个数
#define STR "D"//一级目录名称
#define MAX_USERNAME_LEN 10//用户名长度
#define MAX_PASSWORD_LEN 10//用户密码长度
#define MAX_USERS_NUM 16//最多用户数量
typedef struct User {
char username[MAX_USERNAME_LEN + 1];//用户名
char password[MAX_PASSWORD_LEN + 1];//用户密码
}User;
typedef struct FileNode//文件结构体
{
char fileName[MAX_NameLength];//文件名
struct FileNode* next;//同级目录的下一个文件
char content[MAX_ContentLength];//文件内容
}FileNode;
typedef struct FolderNode//文件夹结构体
{
char folderName[MAX_NameLength];//文件夹名
struct FolderNode* next;//同级目录的下一个文件夹
struct FolderNode* nextFolder;//下一级目录的文件夹
struct FolderNode* previous;//前一个文件夹结构体
struct FileNode* nextFile;//下一级目录的文件
struct FileNode* SameLevelFileHead;//同级文件头结点,只有头结点才有
bool is_Head;//是否头结点
}FolderNode;
void initialFirstHead(FileNode** FirstFileHead, FolderNode** FirstFolderHead);//初始化一级目录头结点
void initial(FileNode** file, FolderNode** folder, FolderNode* head);//初始化文件夹链表的头结点、文件链表头结点
void AddFolder(FolderNode* head); //同级增加文件夹
void AddFile(FileNode* head);//同级增加文件
void PrintDirectory(FolderNode* folderHead, FileNode* fileHead);//打印文件目录
void OpenFile(FileNode* fileHead);//打印文件
void OpenFolder(FileNode** fileHead, FolderNode** folderHead);//打开文件夹
bool StartInterface();//开始界面
void PrintSystemName(FolderNode* folderHead);//打印当前路径
void MainMenu();//主菜单
void SelectMenu(FileNode** fileHead, FolderNode** folderHead);//选择菜单
void ClearScreen()//清屏
{
system("cls"); //for Windows
//system("clear"); //for Linux
}
void FreeBuffer() //吸收输入选项的回车
{
while (getchar() != '\n') {//抵消输入选项时的回车
continue;
}
}
void AnyContinue() //按任意键继续
{
printf("按任意键继续...\n");
getchar();
}
void initialFirstHead(FileNode** FirstFileHead, FolderNode** FirstFolderHead)//初始化一级目录头结点
{
*FirstFileHead = (FileNode*)malloc(sizeof(FileNode));
(*FirstFileHead)->next = NULL;
*FirstFolderHead = (FolderNode*)malloc(sizeof(FolderNode));
(*FirstFolderHead)->next = NULL;
(*FirstFolderHead)->nextFile = NULL;
(*FirstFolderHead)->nextFolder = NULL;
(*FirstFolderHead)->previous = NULL;
(*FirstFolderHead)->is_Head = true;
(*FirstFolderHead)->SameLevelFileHead = *FirstFileHead;
strcpy((*FirstFolderHead)->folderName, STR);
}
void initial(FileNode** file, FolderNode** folder, FolderNode* head)//初始化文件夹链表的头结点、文件链表头结点
{
*file = (FileNode*)malloc(sizeof(FileNode));
(*file)->next = NULL;
*folder = (FolderNode*)malloc(sizeof(FolderNode));
(*folder)->next = NULL;
(*folder)->nextFile = NULL;
(*folder)->nextFolder = NULL;
(*folder)->previous = head;
head->nextFile = *file;
head->nextFolder = *folder;
(*folder)->is_Head = true;
(*folder)->SameLevelFileHead = *file;
strcpy((*folder)->folderName, head->folderName);
}
void AddFolder(FolderNode* head) //同级增加文件夹
{
FolderNode* r = head;
while (r->next != NULL) {
r = r->next;
}
FolderNode* node = (FolderNode*)malloc(sizeof(FolderNode));
node->next = NULL;
node->nextFile = NULL;
node->nextFolder = NULL;
node->is_Head = false;
node->previous = r;
node->SameLevelFileHead = NULL;
FreeBuffer();
while (1) {// 输入并验证文件夹名
printf("请输入文件夹名,限%d字符以内,按回车键结束输入:", MAX_NameLength);
fgets(node->folderName, MAX_NameLength + 1, stdin);
int len = strlen(node->folderName);
if (node->folderName[len - 1] == '\n') {
node->folderName[len - 1] = '\0';
}
if (strlen(node->folderName) == 0) {// 检查文件夹名是否符合规范
printf("文件夹名不能为空,请重新输入!\n");
}
else if (strlen(node->folderName) > MAX_NameLength) {
printf("文件夹名长度不能超过%d个字符,请重新输入!\n", MAX_NameLength);
}
else if (node->folderName[0] == ' ') {
printf("文件夹名不能以空格开头,请重新输入!\n");
}
else {
FolderNode* folder = head->next;
while (folder) {// 检查文件夹名是否重复
if (strcmp(node->folderName, folder->folderName) == 0) {
printf("已存在同名文件夹,请重新输入!\n");
break;
}
folder = folder->next;
}
if (!folder) {
break;
}
}
}
printf("文件夹创建成功!\n");
AnyContinue();
r->next = node;
}
void AddFile(FileNode* head)//同级增加文件
{
FileNode* r = head;
while (r->next != NULL) {
r = r->next;
}
FileNode* node = (FileNode*)malloc(sizeof(FileNode));
node->next = NULL;
FreeBuffer();
while (1) {// 输入并验证文件名
printf("请输入文件名,限%d字符以内,按回车键结束输入:", MAX_NameLength);
fgets(node->fileName, MAX_NameLength + 1, stdin);
int len = strlen(node->fileName);
if (node->fileName[len - 1] == '\n') {
node->fileName[len - 1] = '\0';
}
if (strlen(node->fileName) == 0) {// 检查文件名是否符合规范
printf("文件名不能为空,请重新输入!\n");
}
else if (strlen(node->fileName) > MAX_NameLength) {
printf("文件名长度不能超过%d个字符,请重新输入!\n", MAX_NameLength);
}
else if (node->fileName[0] == ' ') {
printf("文件名不能以空格开头,请重新输入!\n");
}
else {
FileNode* file = head->next;
while (file) {// 检查文件名是否重复
if (strcmp(node->fileName, file->fileName) == 0) {
printf("已存在同名文件,请重新输入!\n");
break;
}
file = file->next;
}
if (!file) {
break;
}
}
}
while (1) {// 输入并验证文件内容
printf("请输入文件内容,限%d字符以内,按回车键结束输入:\n", MAX_ContentLength);
fgets(node->content, MAX_ContentLength + 1, stdin);
int len = strlen(node->content);
if (node->content[len - 1] == '\n') {
node->content[len - 1] = '\0';
}
// 检查文件内容是否符合规范
if (strlen(node->content) == 0) {
printf("文件内容不能为空,请重新输入!\n");
}
else if (strlen(node->content) > MAX_ContentLength) {
printf("文件内容长度不能超过%d个字符,请重新输入!\n", MAX_ContentLength);
}
else {
break;
}
}
r->next = node;// 将新文件插入文件链表末尾
printf("文件创建成功!\n");
AnyContinue();
}
void PrintDirectory(FolderNode* folderHead, FileNode* fileHead)//打印文件目录
{
FolderNode* folder = folderHead;
FileNode* file = fileHead;
if (folder->next == NULL && file->next == NULL) {
printf("\n当前目录为空,可新建文件或文件夹!\n\n");
}
else {
int j = 1;
printf("---文件名--------------------类型---------\n");
while (folder->next != NULL) {
printf("%d. %-25s 文件夹\n", j, folder->next->folderName);
folder = folder->next;
j++;
}
while (file->next != NULL) {
printf("%d. %-25s 文件\n", j, file->next->fileName);
file = file->next;
j++;
}
j = 1;
}
}
void OpenFile(FileNode* fileHead)//打印文件
{
FreeBuffer();
char temp[MAX_NameLength + 1];
// 输入并验证文件名
while (1) {
printf("请输入要打开的文件名,按回车键结束输入:", MAX_NameLength);
fgets(temp, MAX_NameLength + 1, stdin);
int len = strlen(temp);
if (temp[len - 1] == '\n') {
temp[len - 1] = '\0';
}
// 检查文件名是否符合规范
if (strlen(temp) == 0) {
printf("文件名不能为空,请重新输入!\n");
}
else if (strlen(temp) > MAX_NameLength) {
printf("文件名长度不能超过%d个字符,请重新输入!\n", MAX_NameLength);
}
else if (temp[0] == ' ') {
printf("文件名不能以空格开头,请重新输入!\n");
}
else {
FileNode* file = fileHead->next;
// 检查文件名是否重复
while (file) {
if (strcmp(temp, file->fileName) == 0) {
ClearScreen();
printf("-------------------------------------------------\n");
printf("---------------------文件内容--------------------\n");
printf("-------------------------------------------------\n\n");
printf("%s\n", file->content);
break;
}
file = file->next;
}
if (!file) {
printf("文件不存在!\n");
}
AnyContinue();
break;
}
}
}
void OpenFolder(FileNode** fileHead, FolderNode** folderHead)//打开文件夹
{
FreeBuffer();
char temp[MAX_NameLength + 1];
// 输入并验证文件夹名
while (1) {
printf("请输入要打开的文件夹名,按回车键结束输入:", MAX_NameLength);
fgets(temp, MAX_NameLength + 1, stdin);
int len = strlen(temp);
if (temp[len - 1] == '\n') {
temp[len - 1] = '\0';
}
// 检查文件名是否符合规范
if (strlen(temp) == 0) {
printf("文件名不能为空,请重新输入!\n");
}
else if (strlen(temp) > MAX_NameLength) {
printf("文件名长度不能超过%d个字符,请重新输入!\n", MAX_NameLength);
}
else if (temp[0] == ' ') {
printf("文件名不能以空格开头,请重新输入!\n");
}
else {
FolderNode* folder = (*folderHead)->next;
// 检查文件名是否重复
while (folder) {
if (strcmp(temp, folder->folderName) == 0) {
/*
* 全靠这几行代码,精华中的精华
* 通过修改指针实现
*/
if (folder->nextFolder == NULL) {
initial(&folder->nextFile, &folder->nextFolder, folder);
}
*fileHead = folder->nextFile;
*folderHead = folder->nextFolder;
break;
}
folder = folder->next;
}
if (!folder) {
printf("文件夹不存在!\n");
}
AnyContinue();
break;
}
}
}
void DeleteFile(FileNode* head)//删除文件
{
char node[MAX_NameLength + 1];
FreeBuffer();
// 输入并验证文件名
while (1) {
printf("请输入要删除的文件名,按回车键结束输入:", MAX_NameLength);
fgets(node, MAX_NameLength + 1, stdin);
int len = strlen(node);
if (node[len - 1] == '\n') {
node[len - 1] = '\0';
}
// 检查文件名是否符合规范
if (strlen(node) == 0) {
printf("文件名不能为空,请重新输入!\n");
}
else if (strlen(node) > MAX_NameLength) {
printf("文件名长度不能超过%d个字符,请重新输入!\n", MAX_NameLength);
}
else if (node[0] == ' ') {
printf("文件名不能以空格开头,请重新输入!\n");
}
else {
FileNode* file = head->next;
FileNode* r = head;
// 检查文件名是否重复
while (file) {
if (strcmp(node, file->fileName) == 0) {
r->next = file->next;
free(file);
break;
}
file = file->next;
r = r->next;
}
if (!file) {
printf("文件不存在!\n");
}
AnyContinue();
break;
}
}
}
void DeleteFolder(FolderNode* head)//删除文件夹
{
char node[MAX_NameLength + 1];
FreeBuffer();
// 输入并验证文件夹名
while (1) {
printf("请输入要删除的文件夹名,按回车键结束输入:", MAX_NameLength);
fgets(node, MAX_NameLength + 1, stdin);
int len = strlen(node);
if (node[len - 1] == '\n') {
node[len - 1] = '\0';
}
// 检查文件名是否符合规范
if (strlen(node) == 0) {
printf("文件夹名不能为空,请重新输入!\n");
}
else if (strlen(node) > MAX_NameLength) {
printf("文件夹名长度不能超过%d个字符,请重新输入!\n", MAX_NameLength);
}
else if (node[0] == ' ') {
printf("文件夹名不能以空格开头,请重新输入!\n");
}
else {
FolderNode* folder = head->next;
FolderNode* r = head;
// 检查文件名是否重复
while (folder) {
if (strcmp(node, folder->folderName) == 0) {
r->next = folder->next;
free(folder);
break;
}
folder = folder->next;
r = r->next;
}
if (!folder) {
printf("文件夹不存在!\n");
}
AnyContinue();
break;
}
}
}
bool StartInterface()//开始界面
{
ClearScreen();
int choice = 0;
int flag1 = 1;
int flag2 = 0;
int flag3 = 0;
int flag4 = 0;
int user_count = 0; // 用户数量
User users[MAX_USERS_NUM]; // 用户数组
// 从文件中读取用户信息
char username[MAX_USERNAME_LEN + 20];
char password[MAX_PASSWORD_LEN + 20];
FILE* fp = fopen("user_info.txt", "r");
if (fp == NULL) {//没有user_info.txt就创建一个
fp = fopen("user_info.txt", "w");
if (fp != NULL) {
fclose(fp);
fp = fopen("user_info.txt", "r");
}
}
while (!feof(fp)) {
int res = fscanf(fp, "%s %s\n", username, password);
if (res != 2) {
break;
}
strcpy(users[user_count].username, username);
strcpy(users[user_count].password, password);
user_count++;
}
fclose(fp);
do {
if (flag1) {
printf("1.注册\n");
printf("2.登录\n");
printf("0.退出\n");
printf("---------------------\n");
printf("请输入您的选择:");
}
flag1 = 1;
scanf("%d", &choice);
FreeBuffer();
switch (choice)
{
case 1:// 注册
// 用户数量不能超过上限
if (user_count >= MAX_USERS_NUM) {
printf("用户数量已达上限!\n");
AnyContinue();
}
else {
printf("用户名限%d字符,密码限%d字符,不含空格\n", MAX_USERNAME_LEN, MAX_PASSWORD_LEN);
while (1) {
flag3 = 0;
printf("用户名: ");
fgets(username, MAX_USERNAME_LEN + 20, stdin);
int len = strlen(username);
if (username[len - 1] == '\n') {
username[len - 1] = '\0';
}
// 检查文件名是否符合规范
if (strlen(username) == 0) {
flag3 = 1;
printf("用户名不能为空,请重新输入!\n");
}
else if (strlen(username) > MAX_USERNAME_LEN) {
flag3 = 1;
printf("用户名长度不能超过%d个字符,请重新输入!\n", MAX_USERNAME_LEN);
}
else{
for (int i = 0; i < strlen(username); i++) {
if (isspace(username[i])) {
printf("用户名中不能包含空格,请重新输入!\n");
flag3 = 1;
break;
}
}
}
if(flag3==0) {
int flag = 1;
for (int i = 0; i < user_count; i++) {// 用户名不能重复
if (strcmp(users[i].username, username) == 0) {
flag = 0;
printf("用户名已存在!\n");
}
}
if (flag == 1) {
while (1) {
flag4 = 0;
printf("密码: ");
fgets(password, MAX_PASSWORD_LEN + 20, stdin);
int len = strlen(password);
if (password[len - 1] == '\n') {
password[len - 1] = '\0';
}
// 检查文件名是否符合规范
if (strlen(password) == 0) {
flag4 = 1;
printf("文件夹名不能为空,请重新输入!\n");
}
else if (strlen(password) > MAX_PASSWORD_LEN) {
flag4 = 1;
printf("密码长度不能超过%d个字符,请重新输入!\n", MAX_PASSWORD_LEN);
}
else {
for (int i = 0; i < strlen(password); i++) {
if (isspace(password[i])) {
printf("密码中不能包含空格,请重新输入!\n");
flag4 = 1;
break;
}
}
}
if (flag4 == 0) {
break;
}
}
strcpy(users[user_count].username, username);
strcpy(users[user_count].password, password);
user_count++;
fp = fopen("user_info.txt", "w+");
for (int i = 0; i < user_count; i++) {
fprintf(fp, "%s %s\n", users[i].username, users[i].password);
}
fclose(fp);
printf("注册成功!\n");
AnyContinue();
break;
}
else {
printf("1重新输入,0退出注册:");
int c = 0;
while (1) {
scanf("%d", &c);
FreeBuffer();
if (c == 0 || c == 1) {
break;
}
else {
printf("无效的选项,请重新输入:");
}
}
if (c == 0) {
break;
}
}
}
}
}
ClearScreen();
break;
case 2: // 登录
printf("请输入用户名和密码!\n");
while (1) {
printf("用户名: ");
scanf("%s", username);
printf("密码: ");
scanf("%s", password);
int found = 0;
for (int i = 0; i < user_count; i++) {// 校验用户名和密码
if (strcmp(users[i].username, username) == 0 && strcmp(users[i].password, password) == 0) {
printf("登录成功!\n");
flag2 = 1;
FreeBuffer();
AnyContinue();
ClearScreen();
found = 1;
break;
}
}
if (!found) {
printf("用户名或密码错误!\n");
printf("1重新输入,0退出登录:");
int b = 0;
while (1) {
scanf("%d", &b);
if (b == 0 || b == 1) {
break;
}
else {
printf("无效的选项,请重新输入:");
}
}
if (b == 0) {
ClearScreen();
break;
}
}
else {
break;
}
}
break;
case 0:
ClearScreen();
printf("感谢您的使用!");
break;
default:
printf("无效的选项,请重新输入:");
flag1 = 0;
break;
}
} while (choice != 0 && flag2 != 1);
if (choice == 0) {
return false;
}else{
return true;
}
}
void PrintSystemName(FolderNode* folderHead)//打印当前路径
{
printf("-------------------文件管理系统------------------\n");
printf("-------------------------------------------------\n");
printf("--当前路径:");
FolderNode* folder = folderHead;
char files[MAX_RouteLength][MAX_NameLength];/* 定义文件名二维数组,每行存储一个文件名 */
int num_files = 0;
while (1) {/* 遍历文件名数组,先进后出 */
if (folder->previous == NULL) {
strcpy(files[num_files], folder->folderName);
num_files++;
break;
}
if (folder->is_Head) {
strcpy(files[num_files], folder->folderName);
num_files++;
}
folder = folder->previous;
}
for (int i = num_files - 1; i >= 0; i--)
{
if (i == num_files - 1) {
printf("%s:\\\\", files[i]);
}
else {
printf("%s\\\\", files[i]);
}
}
printf("\n---------------------------------------------------------\n");
}
void GoBack(FileNode** fileHead, FolderNode** folderHead)//返回上一级
{
FreeBuffer();
FolderNode* folder = *folderHead;
if (folder->previous == NULL) {
printf("已经为第一级目录!\n");
}
else {
FolderNode* prevFolder = folder->previous;// 向前逐个找文件夹结构体
while (1) {
if (prevFolder->is_Head == true) {
break;
}
prevFolder = prevFolder->previous;
}// 此时 prevFolder 即为同级前一个文件夹的头结点
*folderHead = prevFolder;
*fileHead = prevFolder->SameLevelFileHead;
}
AnyContinue();
}
void MainMenu()//主菜单
{
printf("-------------------------------------\n");
printf("---1.新建文件------------\n");
printf("---2.新建文件夹----------\n");
printf("---3.打开文件------------\n");
printf("---4.打开文件夹----------\n");
printf("---5.删除文件------------\n");
printf("---6.删除文件夹----------\n");
printf("---7.返回上一级----------\n");
printf("---8.用户退出------------\n");
printf("---0.退出系统------------\n");
printf("-------------------------------------\n");
}
void SelectMenu(FileNode** fileHead, FolderNode** folderHead)//选择菜单
{
int flag2 = 0;
if (StartInterface()) {
int choice = 0;//选择
int flag = 1;//无效的选项不需要再打印菜单
do {
if (flag) {
PrintSystemName(*folderHead);
PrintDirectory(*folderHead, *fileHead);
MainMenu();
printf("请输入您的选择:");
}
flag = 1;
scanf("%d", &choice);
switch (choice)
{
case 1:
AddFile(*fileHead);
ClearScreen();
break;
case 2:
AddFolder(*folderHead);
ClearScreen();
break;
case 3:
OpenFile(*fileHead);
ClearScreen();
break;
case 4:
OpenFolder(fileHead, folderHead);
ClearScreen();
break;
case 5:
DeleteFile(*fileHead);
ClearScreen();
break;
case 6:
DeleteFolder(*folderHead);
ClearScreen();
break;
case 7:
GoBack(fileHead, folderHead);
ClearScreen();
break;
case 8:
ClearScreen();
printf("用户登出成功!\n");
FreeBuffer();
AnyContinue();
ClearScreen();
if (!StartInterface()) {
flag2 = 1;
}
break;
case 0:
ClearScreen();
printf("感谢您的使用!");
break;
default:
printf("无效的选项,请重新输入:");
flag = 0;
break;
}
} while (choice != 0&&flag2==0);
if (flag2 == 0) {
ClearScreen();
printf("感谢您的使用!");
}
}
}
int main()
{
FileNode* FirstFileHead;//一级文件链表头结点
FolderNode* FirstFolderHead;//一级文件夹链表头结点
initialFirstHead(&FirstFileHead, &FirstFolderHead);
SelectMenu(&FirstFileHead, &FirstFolderHead);
return 0;
}
运行效果
具体功能如运行图