操作系统课程设计——文件管理模拟 C++版

不蒸馒头曾口气 2024-06-16 17:35:09 阅读 77

参考博客:【操作系统之模拟文件管理系统 - CSDN App】

并在此基础上进行了修改和完善部分代码

这是我的第一篇CSDN,内容有点长


实验内容

文件管理

一、目的

通过模拟磁盘,完成操作系统的文件管理功能,掌握包括目录结构的管理、外存空【操作系统之模拟文件管理系统 - CSDN App】间的分配与释放以及空闲空间管理三部分。为写入模拟磁盘的数据文件建立目录,目录可以是单级文件目录、双级文件目录、树形结构目录。在目录中选择某个文件可以将其数据读入模拟内存。

二、设计内容

通过初始化操作建立一个模拟磁盘,在模拟磁盘中保存目录和文件内容。创建该模拟磁盘时可创建初始的根目录内容、文件分配表。文件目录项(可以采用FCB格式)应包括文件名、类型(目录 or文件)、创建日期、大小、第一个磁盘块块号。目录管理需支持:

新建目录:在目录中新建空目录; 删除目录:删除空目录

为文件建立目录项:一个文件创建成功后,为该文件创建目录项,并将文件和相关信息写入目录;

删除文件:删除目录中某个文件,删除其在磁盘中的数据,并删除目录项。如果被删除文件已经读入内存应阻止删除,完成基本的文件保护。

三、 设计要求

不同的功能使用不同的函数实现(模块化),对每个函数的功能和调用接口要注释清楚。对程序其它部分也进行必要的注释。对系统进行功能模块分析、画出总流程图和各模块流程图。用户界面要求使用方便、简洁明了、美观大方、格式统一。所有功能可以反复使用,最好使用菜单。通过命令行相应选项能直接进入某个相应菜单选项的功能模块。所有程序需调试通过。

实验说明

本实验是参考了http://t.csdnimg.cn/B0Fqh

 ,并在此基础上进行了修改和完善部分代码。

本次实验为Linux系统设计了一个简单的二级文件系统,可以做到以下几点:

可用命令及说明 register 用户的注册login 用户的登入cd 切换目录mkdir 创建用户的子目录rmdir 删除用户的子目录dir 显示当前目录的子目录create 创建文件夹的文件del 删除文件夹的文件open 打开文件close 关闭文件read 读文件write 写文件set 设置文件的保护码exit 退出系统look 查看系统中的所有用户fatused 查看目前块的状态用户登入时会对用户名和密码进行匹配进入系统的第一步需要注册账号并登入(为测试方便,初始化了一个用户)在创建子目录时必须先登入不可在打开的状态下进行任何删除操作删除子目录或文件时释放其空间创建文件和打开文件时必须先进入文件夹文件被打开后可进行读写操作文件保护码为2可读可写,为0不可读,其他不可写

文件结构

这些图表是我的一点理解,可能存在偏差

用户文件结构

打开文件结构

创建文件流程图

删除文件流程图

代码说明

整体结构

#define BLOCK_SIZE 512 //每一个磁盘块的大小#define BLOCK_NUM 64 //磁盘块数量#define MAX_FILE_NUM16 //每个文件夹的最大文件数#define MAX_FOLDER_NUM 16 //每个用户可以拥有的最大文件夹数#define MAX_OPEN_FILE_NUM 16 //最大同时打开文件数#define MAX_USER_NUM16 //最大用户数

主目录 存放用户数据结构 最大可存放16个用户用户名密码指向用户的指针

struct MFD//用户数据结构{string username;//用户名string password;//密码struct USER_UFD *next;//指向用户文件的指针};

子目录(文件夹数据结构)

各个用户所拥有的目录最大创建16个目录(及文件)其中包含文件数据结构文件夹名字当前文件夹的文件数

文件数据结构

文件名(同文件下不可重名)文件保护码(默认为2 可读可写,为0 不可读)文件长度(长度超过块的存储范围会找下一个块)文件起始地址文件创建日期是否占用

struct UFD//文件夹数据结构 {struct file_message//文件数据结构{string filename;//文件名int protect_code;//文件保护码int length;//文件长度int addr;//文件起始地址string time;//日期时间,格式为yyyymmdd hhmmss int used;//是否被占用 0:空闲 1:占用}ufd[MAX_FILE_NUM];//一个文件夹最对可以有16个文件string directname;//文件夹名字int cur_file_size = 0;//当前该文件夹含有的文件数量};

打开的文件数据结构 最多打开16个文件文件名字文件长度文件保护码文件起始地址当前打开的文件数量

struct UOF//打开文件数据结构{struct uof{string filename;//文件名字int pointer;//文件长度int protect_code;//文件保护码 默认2 2为可读可写 0为不可读 其余数字不可写int addr;//文件起始地址}uof[MAX_OPEN_FILE_NUM];//最多可以同时打开16个文int cur_openfilesize = 0;//当前打开的文件数量};

块号数据结构 存放下一页的块号块号的状态 (1 占用; 0 空闲)

struct fat//块号{int next = -1;//存放下一页的块号,无为-1int used = 0; //used存在三种状态,1:被占用 0:空闲}fat[BLOCK_NUM];//最大为64

用户文件数据结构 包含文件夹数据结构当前拥有的文件夹数量

struct USER_UFD//用户文件数据结构{struct UFD direct[MAX_FOLDER_NUM];//一个用户最多可以有16个文件夹int cur_user_direct_size = 0;//当前拥有的文件夹数量};

定义属性及函数声明

int mark = 1;struct USER_UFD cur_user_all_direct_array[MAX_USER_NUM];//用户文件数组 16struct MFD cur_user;//当前用户struct UOF * cur_opentable;//指向打开文件数组的指针char *fdisk;//模拟磁盘指针struct UOF openfile[MAX_OPEN_FILE_NUM];//每一个用户对应一个文件打开表对象,16struct MFD mfd[MAX_USER_NUM]; //16个用户int cur_user_size = 0;//记录当前用户的人数string path;int REGISTER();//注册用户int LOGIN();//登录用户int CREATE(string name);//创建文件int DELETE(string name);//删除文件int OPEN(string name);//打开文件int WRITE(string name);//写文件int READ(string name);//读文件int CLOSE(string name);//关闭文件int CD();//更改当前目录int MKDIR(string name);//创建文件夹int DIR();//显示当前目录的子目录int SET(string name, int protectcode);//设置保护码void INPUT_OPERATION();//指令输入

main函数

初始化一个用户方便调试代码

并输出命令格式说明

int main(){cur_user.username = "";path = "";fdisk = (char *)malloc(1024 * 1024 * sizeof(int));//模拟硬盘指针//注册root用户并登录,方便调试代码mfd[cur_user_size].username = "root";mfd[cur_user_size].password = "123456";cur_user_size++;mfd[0].next = &(cur_user_all_direct_array[0]);cur_user = mfd[0];cur_user.next->cur_user_direct_size = mfd[0].next->cur_user_direct_size;cur_user_size++;cur_opentable = &openfile[cur_user_size]; //指针指向文件打开表对象cur_opentable->cur_openfilesize = 0;cout << "*******************欢迎使用二级文件系统*******************" << endl;cout << " 命令格式 说明 " << endl;cout << " register 注册用户 " << endl;cout << " login 登录 " << endl;cout << " cd 目录名 更改当前目录 " << endl;cout << " mkdir 目录名 创建子目录 " << endl;cout << " rmdir 目录名 删除子目录 " << endl;cout << " dir 显示当前目录的子目录 " << endl;cout << " create 文件名 创建文件 " << endl;cout << " del 文件名 删除文件 " << endl;cout << " open 文件名 打开文件 " << endl;cout << " close 关闭文件 " << endl;cout << " read 文件名 读文件 " << endl;cout << " write 文件名 写文件 " << endl;cout << " set 文件名 文件保护码 设置文件保护码 " << endl;cout << " exit 退出系统 " << endl;cout << " look 查看用户 " << endl;cout << " fatused 查看块 " << endl;while (mark)INPUT_OPERATION();free(fdisk);return 1;}

INPUT_OPERATION函数(指令输入)

开始运行文件管理系统时是未登入的状态(现在代码是默认初始化一个用户)

未登录时显示localhost :

登入后显示cur_user.username@localhost home/ path:(用户名+@localhost home/: )刚登入时path=""

然后通过cin >> operaton;输入控制语句,进行匹配调用不同的函数

void INPUT_OPERATION()//指令输入{if (cur_user.username == "")cout << "localhost :";elsecout << cur_user.username << "@localhost home/" << path << ":";string operaton;cin >> operaton;if (operaton == "login"){LOGIN();}else if (operaton == "create"){string filename;cin >> filename;CREATE(filename);}else if (operaton == "del"){string name;cin >> name;DELETE(name, -1);}else if (operaton == "open"){string name;cin >> name;OPEN(name);}else if (operaton == "close"){string name;cin >> name;CLOSE(name);}else if (operaton == "write"){string content;string name;cin >> name;WRITE(name);}else if (operaton == "read"){string name;cin >> name;READ(name);}else if (operaton == "exit"){exit(0);}else if (operaton == "cd"){CD();}else if (operaton == "dir"){DIR();}else if (operaton == "mkdir"){string name;cin >> name;MKDIR(name);}else if (operaton == "register"){REGISTER();}else if (operaton == "exit"){mark = 0;}else if (operaton == "set"){string name;int protextcode;cin >> name;cin >> protextcode;SET(name, protextcode);}else if (operaton == "rmdir"){string name;cin >> name;RMDIR(name);}else if (operaton == "look"){LOOK();}else if (operaton == "fatused"){fatused();}else{cout << "命令错误,请重新输入" << endl;}}

REGISTER函数(用户注册)

输入用户名和密码

先对比用户数据结构数组(struct UOF openfile[MAX_OPEN_FILE_NUM])中的用户名,用户名重复则失败,否则成功,并将用户信息存入用户结构体中

int REGISTER()//注册用户{cout << "请输入用户名:";string username;cin >> username;cout << "请输入密码:";string password;cin >> password;for (int i = 0; i < MAX_USER_NUM; i++)//最大可有16个用户{if (mfd[i].username == username){cout << "注册失败,该用户名已存在" << endl;return 0;}}//将用户信息存入用户结构体中mfd[cur_user_size].username = username;mfd[cur_user_size].password = password;cur_user_size++;cout << "注册成功" << endl;return 1;}

LOGIN函数(用户登入)

把输入的用户名和密码与记录所有用户的结构体数组进行比对,

比对成功后将此用户文件的指针加入到当前用户文件数组中,并设置此为当前目录(即当前用户下)

并指向当前用户的文件打开表对象

int LOGIN()//用户登入{cout << "请输入用户名:";string username;cin >> username;cout << "请输入密码:";string password;cin >> password;int i;for (i = 0; i < cur_user_size; i++){if (mfd[i].username == username){if (mfd[i].password != password){cout << "密码错误" << endl;return 0;}else{break;}}}if (i == cur_user_size){cout << "没有此用户" << endl;return 0;}mfd[i].next = &(cur_user_all_direct_array[i]);//用户文件指向第i个用户数组cur_user = mfd[i];//登入后此为当前目录cur_user.next->cur_user_direct_size = mfd[i].next->cur_user_direct_size;//让当前用户找到所登入的用户文件cur_user_size++;//用户人数+1cur_opentable = &openfile[cur_user_size]; //指针指向文件打开表对象 每一个用户一个文件打开表对象,该表中最多存放16个文件夹cur_opentable->cur_openfilesize = 0;//设置当前打开的文件数为0path = "";//设置path在刚登入时为空return 1;}

LOOK函数(查看所有用户)

遍历用户名,方便观察调试

//查看用户表int LOOK(){int i;for (i = 0; i < cur_user_size; i++){cout << mfd[i].username << " ";//遍历现有的用户数,方便观察}printf("\n"); return 1;}

getCurrentTimeStr函数(获取当前时间)

string getCurrentTimeStr()//得到时间{time_t t = time(NULL);char ch[64] = { 0};strftime(ch, sizeof(ch) - 1, "%Y-%m-%d %H:%M:%S", localtime(&t));return ch;}

CREATE函数(创建文件)

必须先进入文件夹在创建文件找到对应文件夹判断文件是否重名判断该文件夹中的文件是否满16个判断是否有空闲块条件满足创建,否则输出提示

更新文件数据,文件数量+1,磁盘块占用

//创建文件int CREATE(string name){int index;if (path == ""){cout << "请先进入文件夹,再创建文件" << endl;return 0;}for (index = 0; index < cur_user.next->cur_user_direct_size; index++){if (path == cur_user.next->direct[index].directname)//如果path等于文件夹名{break;}}int i;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//循环当前文件夹的文件数{if (name == cur_user.next->direct[index].ufd[i].filename){break;//文件名重复跳出循环}}if (i < cur_user.next->direct[index].cur_file_size)//重复 i会小于文件数,无重复 则等于{cout << "文件名重复" << endl;return 0;}if (cur_user.next->direct[index].cur_file_size == MAX_OPEN_FILE_NUM){cout << "该文件夹文件已达到"<< MAX_OPEN_FILE_NUM << "个" << endl;return 0;}int j;for (j = 0; j < BLOCK_NUM; j++)//判断是否有空闲块 磁盘块数量64 每个块大小512{if (fat[j].used == 0){break;}}if (j >= BLOCK_NUM){cout << "磁盘没有空闲块了" << endl;return 0;}string tim=getCurrentTimeStr();cout << tim << endl;cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].time = tim;//创建时间cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].filename = name;//上面都通过了保存文件名cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].addr = j; //文件起始盘块号cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].length = 0;//未写入数据,长度为0cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].protect_code = 2; //表示可读可写//cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].time = tim;//创建时间cur_user.next->direct[index].cur_file_size++;//用户文件数量加1 fat[j].used = 1;//此时已被占用return 1;}

DELETE函数(删除文件)

判断是否在文件中循环找到文件夹循环找到文件判断文件是否打开(打开时文件不可删除)删除文件或输出提示

更新文件数组信息,将最后一个文件替换到删除的文件中

如果已经是最后一个文件,则直接删除

//删除文件int DELETE(string name, int mark){if (path == "" && mark == -1){cout << "请在文件夹中删除文件" << endl;return 0;}int index;if(mark != -1) //如果是被RMDIR函数调用,则当前path=""index = mark;elsefor (index = 0; index < cur_user.next->cur_user_direct_size; index++)//循环用户拥有的文件夹{if (path == cur_user.next->direct[index].directname)//找到文件夹后退出{break;}}int i;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//循环该文件夹的文件{if (cur_user.next->direct[index].ufd[i].filename == name)//找到文件后退出{break;}}if (i >= cur_user.next->direct[index].cur_file_size){cout << "没有该文件" << endl;return 0;}int j;for (j = 0; i < cur_opentable->cur_openfilesize; j++)//循环打开的文件,查看是否被打开{if (cur_opentable->uof[j].filename == name)break;}if (j < cur_opentable->cur_openfilesize){cout << "该文件已被打开,无法删除" << endl;return 0;}//更新当前用户目录下文件数组信息,就是将最后一个文件的信息替换到要删除的文件的位置//如果本身是最后一个文件,那么不需要替换,直接删除if(i == cur_user.next->direct[index].cur_file_size -1){fat[cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].addr].used = 0; cur_user.next->direct[index].cur_file_size--;//next为-1 说明没有下一页,此为最后一页int temp = fat[cur_user.next->direct[index].ufd[i].addr].next;while (temp != -1)//删除该文件的内存空间{fat[temp].used = 0;temp = fat[temp].next;}cout << "删除文件" << name << "成功" << endl;return 1;}else{cur_user.next->direct[index].ufd[i].filename = cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].filename;//先将该块置0fat[cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].addr].used = 0; cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].addr = cur_user.next->direct[index].ufd[i].addr;cur_user.next->direct[index].ufd[i].length = cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].length;cur_user.next->direct[index].ufd[i].protect_code = cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].protect_code;cur_user.next->direct[index].cur_file_size--;//将该文件设置为占用fat[cur_user.next->direct[index].ufd[i].addr].used = 1;//next为-1 说明没有下一页,此为最后一页int temp = fat[cur_user.next->direct[index].ufd[i].addr].next;while (temp != -1)//删除该文件的内存空间{fat[temp].used = 0;temp = fat[temp].next;}cout << "删除文件" << name << "成功" << endl;return 1;}}

OPEM函数(打开文件)

判断是否在文件夹中循环文件夹数,找到要打开文件所在的文件夹循环文件数,找到文件判断打开的文件数是否满16判断文件是否已经打开将文件信息加入到已打开的文件数组中打开文件

int OPEN(string name)//打开文件{ if (path == ""){cout << "请在文件夹中打开文件" << endl;return 0;}string AllName = path +'/'+name;//设置该变量的原因是防止出现打开文件数组中存在文件夹名不同而文件同名的情况int index;for (index = 0; index < cur_user.next->cur_user_direct_size; index++)//循环当前用户的文件{if (path == cur_user.next->direct[index].directname){ break;}}int i = 0;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//循环文件数{if (name == cur_user.next->direct[index].ufd[i].filename)//找到同名文件 break;}if (i >= cur_user.next->direct[index].cur_file_size){cout << "没有该文件" << endl;return 0;}if (cur_opentable->cur_openfilesize == MAX_OPEN_FILE_NUM){cout << "文件打开数量已经达到最大值" << endl;return 0;}for (int j = 0; i < cur_opentable->cur_openfilesize; j++){if (cur_opentable->uof[i].filename == AllName)//在打开文件中找到相应文件夹中的文件{ cout << "该文件已经打开" << endl; return 0;}}int k;for (k = 0; k < cur_user.next->direct[index].cur_file_size; k++){if (cur_user.next->direct[index].ufd[k].filename == name)//找到相应文件夹中的文件 break;} //将该文件的信息加入到已打开的文件数组中cur_opentable->uof[cur_opentable->cur_openfilesize].filename = AllName;//在打开的文件数组中加入该文件cur_opentable->uof[cur_opentable->cur_openfilesize].protect_code = cur_user.next->direct[index].ufd[k].protect_code;//保护码cur_opentable->uof[cur_opentable->cur_openfilesize].pointer = cur_user.next->direct[index].ufd[k].length;cur_opentable->uof[cur_opentable->cur_openfilesize].addr = cur_user.next->direct[index].ufd[k].addr;//起始地址cur_opentable->cur_openfilesize++; //文件打开数量加1cout << "文件打开成功" <<endl;return k; //返回文件在文件打开表中的第几项}

CLOSE函数(关闭文件)

循环打开的文件数,找到文件更新打开文件数组信息将最后一个打开文件的信息替换到要关闭的位置关闭文件

int CLOSE(string name)//关闭文件{int i;for (i = 0; i < cur_opentable->cur_openfilesize; i++){if (cur_opentable->uof[i].filename == path + '/' + name){break;}}if (i >= cur_opentable->cur_openfilesize){cout << "该文将未打开" << endl;return 0;}//更新当前用户打开文件数组信息,就是将最后一个打开文件的信息替换到要关闭的打开文件的位置cur_opentable->uof[i].filename = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].filename;cur_opentable->uof[i].pointer = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].pointer;cur_opentable->uof[i].protect_code = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].protect_code;cur_opentable->uof[i].addr = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].addr;cur_opentable->cur_openfilesize--;cout << "文件关闭成功" << endl;return 1;}

WRITE函数(写入文件)

循环文件夹数,找到文件所在文件夹循环打开文件,判断文件是否已打开判断文件保护码是否可写输入内容更新磁盘空间大小磁盘空间不够写,填满最后一个磁盘块后寻找下一个空闲块写入

int WRITE(string name)//写入文件{int index; //标识当前目录在direct数组中第几个for (index = 0; index < cur_user.next->cur_user_direct_size; index++){if (path == cur_user.next->direct[index].directname)//在当前用户的文件夹中找到相应的文件{break;}}int i;//判读文件是否打开for (i = 0; i < cur_opentable->cur_openfilesize; i++){if (cur_opentable->uof[i].filename == path + '/' + name)//循环打开的文件break;}if (i >= cur_opentable->cur_openfilesize){cout << "文件没有打开, 无法写入" << endl;return -1;}int fd = i; //获取文件描述字//判断读文件的合法性if (cur_opentable->uof[fd].protect_code != 2){cout << "文件不可写" << endl;return -1;}else{string content;//字符串 存储输入的一行内容cin.ignore();//cin.ignore()函数是C++标准输入流(cin)中的一个方法。cin.ignore()函数中有两个参数,//分别为数值型的a 和 字符型的 ch ,即cin.ignore( a, ch )。它表示从输入流 cin 中提取//字符,提取的字符被忽略,不被使用。而每抛弃一个字符,它都要进行计数和比较字符:如果//计数值达到 a 或者被抛弃的字符是 ch ,则cin.ignore() 函数执行终止;否则,它继续等待。//如果默认不给参数的话,默认参数为cin.ignore(1, EOF),即把EOF前的1个字符清掉,没有遇//到EOF就清掉一个字符然后结束。cout << "请输入文件要写入的内容: " << endl;;getline(cin, content); //读入一整行内容int cin_len = content.length();//输入一行的长度int cin_p=0;//初值为0int last_block_res;//磁盘剩余空间的大小//追加写//找到该文件存放的最后一个磁盘块 int last_block = cur_opentable->uof[fd].addr;while (fat[last_block].next != -1){last_block = fat[last_block].next;}int temp;//保存当前所写的文件在用户文件目录表的第几项,为了后面修改文件的大小for (int k = 0; k < cur_user.next->direct[index].cur_file_size; k++){if (cur_user.next->direct[index].ufd[k].filename == name)//找到该文件{temp = k;break;}}//计算该文件存放的最后一个地址char * first;first = fdisk + last_block * BLOCK_SIZE + cur_opentable->uof[fd].pointer % BLOCK_SIZE;//计算最后一个磁盘块还有多少空间if(cur_opentable->uof[fd].pointer == 0)last_block_res = BLOCK_SIZE;else if(cur_opentable->uof[fd].pointer % BLOCK_SIZE == 0)last_block_res = 0;elselast_block_res = BLOCK_SIZE - (cur_opentable->uof[fd].pointer % BLOCK_SIZE);//首先填满最后一个磁盘块if(last_block_res){if(last_block_res <= cin_len)//当最后一个磁盘块的空间小于输入内容大小{for(int j=0;j<last_block_res;j++)first[j] = content[cin_p++];cin_len -= last_block_res;//计算还有多少字符没存入}else//当最后一个磁盘块的空间大于输入内容大小{for(int j=0;j<cin_len;j++)first[j] = content[cin_p++];cur_opentable->uof[fd].pointer = cur_opentable->uof[fd].pointer + cin_len; //更新文件打开表cur_user.next->direct[index].ufd[temp].length = cur_user.next->direct[index].ufd[temp].length + cin_len; //更新用户目录文件表cout << "文件写入成功,共写入" << cin_len << "字节" << endl;return 0;}}//计算还需要多少个磁盘块,判断空间是否足够int times = cin_len / BLOCK_SIZE;//向上取整 求存满块数int offset = cin_len % BLOCK_SIZE;//取余 未存满if (offset != 0)times++;//块数+1int unused_block_num = 0; //记录没有使用过的磁盘块的个数int flag = 0;for (int j = 0; j < BLOCK_NUM; j++){if (fat[j].used == 0){unused_block_num++;}}if(unused_block_num < times)//剩余的块不够写{cout<<"空间不足,写入内容失败!\n";return -1;}int next_block = fat[cur_opentable->uof[fd].addr].next; //记录块的起始地址的nextint first_unused_block; //记录第一个没有被使用过的磁盘for(int j=0;j<times;j++){for (int k = 0; k < BLOCK_NUM; k++){if (fat[k].used == 0){first_unused_block = k;break;}}fat[last_block].next = first_unused_block;last_block = first_unused_block;first = fdisk + last_block * BLOCK_SIZE;if(j!=times-1){for(int k = 0;k<BLOCK_SIZE;k++)first[k] = content[cin_p++];}else{for(int k=0;k<offset;k++)first[k] = content[cin_p++];}}cur_opentable->uof[fd].pointer = cur_opentable->uof[fd].pointer + cin_p; //更新文件打开表cur_user.next->direct[index].ufd[temp].length = cur_user.next->direct[index].ufd[temp].length + cin_p; //更新用户目录文件表cout << "文件写入成功,共写入" << cin_p << "字节" << endl;return 0;}}

READ函数(读文件)

找到文件所在文件夹循环文件数,找到文件判断文件是否打开判断文件是否可读借助缓冲区输出文件内容释放缓冲区

int READ(string name)//读文件{int index1; //标识当前目录在direct数组中第几个for (index1 = 0; index1 < cur_user.next->cur_user_direct_size; index1++){if (path == cur_user.next->direct[index1].directname)//找到文件夹{break;}}int a;for (a = 0; a < cur_user.next->direct[index1].cur_file_size; a++) //判断文件是否存在{if (cur_user.next->direct[index1].ufd[a].filename == name)//找文件break;}if (a >= cur_user.next->direct[index1].cur_file_size){cout << "没有这个文件" << endl;return 0;}int i;//判读文件是否打开for (i = 0; i < cur_opentable->cur_openfilesize; i++){if (cur_opentable->uof[i].filename == path + '/' + name)break;}if (i >= cur_opentable->cur_openfilesize){cout << "文件没有打开, 无法读取" << endl;return -1;}int fd = i; //获取文件描述字//判断读文件的合法性if (cur_opentable->uof[fd].protect_code == 0) //我们创建的文件都是默认可读可写的{cout << "文件不可读" << endl;return 0;}else{int len = cur_opentable->uof[fd].pointer; //文件的长度int block_num = len / BLOCK_SIZE; //磁盘的个数int offset = len % BLOCK_SIZE; //偏移量if (offset != 0)block_num++;//如果我用一个文件表示磁盘的引导块,用另一个文件表示磁盘的数据块,那么我们计算文件的起始位置就不用加上磁盘的引导块了吧//关于文件的存放文件,我们char *fdisk表示一整个磁盘,然后不同文件的内容存放在这个指针所指向的不同字符段char * first = fdisk + cur_opentable->uof[fd].addr * BLOCK_SIZE; //文件的起始地址 第0块起始地址为0 第1块起始地址为512char * buf = (char *)malloc(513 * sizeof(char)); //缓冲区 给指针申请513个char类型大小的空间 512个空间存放内容 第513个存\0cout << "文件的内容为 :";for (int k = 0; k < block_num; k++){if (k == block_num - 1) //则是最后一个磁盘块{int j;for (j = 0; j < len - k * BLOCK_SIZE; j++) //赋值文件剩余的字符,其实就是偏移量{buf[j] = first[j];}buf[j] = '\0';//\0结束printf("%s\n", buf); //输出文件的内容}else //不在最后一个磁盘块,也就是在其他已经读满的磁盘块{int j;for (j = 0; j < BLOCK_SIZE; j++)buf[j] = first[j]; //缓冲区读满就输出内容buf[j] = '\0';printf("%s", buf); //输出文件的内容int next_block = fat[cur_opentable->uof[fd].addr].next; //读完一个磁盘块后,在接着读下一个磁盘块first = fdisk + next_block * BLOCK_SIZE;}}cout << endl;free(buf); //释放缓冲区return 0;}}

CD函数(更改当前目录)

判断是否在根目录循环寻找文件夹找到则更改path值

int CD()//更改当前目录{string temp_path;cin >> temp_path;if (temp_path == ".."){if(path == ""){cout << "已在根目录" << endl;}else{path = ""; }return 1;}int i;for (i = 0; i < cur_user.next->cur_user_direct_size; i++){if (temp_path == cur_user.next->direct[i].directname)break;}if (i >= cur_user.next->cur_user_direct_size){cout << "没有此目录" << endl;return 0;}path = temp_path;//path为该路径return 1;}

MKDIR函数(创建目录)

判断用户目录是否已达16判断目录是否已存在(重名)创建目录

int MKDIR(string name)//创建目录{if (cur_user.next->cur_user_direct_size == MAX_USER_NUM){cout << "用户目录数量已经达到最大值" << endl;return 0;}int i;for (i = 0; i < cur_user.next->cur_user_direct_size; i++){if (cur_user.next->direct[i].directname == name)break;}if (i < cur_user.next->cur_user_direct_size){cout << "该目录名已存在" << endl;return 0;}cur_user.next->direct[cur_user.next->cur_user_direct_size].directname = name;cur_user.next->direct[cur_user.next->cur_user_direct_size].cur_file_size = 0; //新创建的目录里面的文件个数为0cur_user.next->cur_user_direct_size++;cout << "创建目录成功" << endl;return 1;}

RMDIR函数(删除目录)

判断是否在根目录找到文件夹位置判断是否其中有文件打开删除该文件夹的所有文件将最后一个文件夹的位置替换为删除的文件夹的位置目录-1成功删除

int RMDIR(string name)//删除目录{if(path != ""){cout << "请先退出文件夹" << endl;return 0;}int index;//文件夹的位置for (index = 0; index < cur_user.next->cur_user_direct_size; index++)//先判断是否有该文件夹{if (name == cur_user.next->direct[index].directname)break;}for (int i = 0; i < cur_user.next->direct[index].cur_file_size; i++){for(int j=0;i<cur_opentable->cur_openfilesize;j++)if (name + '/' + cur_user.next->direct[index].ufd[i].filename == cur_opentable->uof[j].filename){cout << "请先关闭该文件夹的所有文件" << endl;return 0;}}//删除该文件夹的所有文件for (int i = 0; i < cur_user.next->direct[index].cur_file_size; i++){DELETE(cur_user.next->direct[index].ufd[i].filename, index);}//把最后一个文件的位置放到删除的位置cur_user.next->direct[index].cur_file_size = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].cur_file_size; //注意这里需要减一,由于本身结构的限制cur_user.next->direct[index].directname = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].directname;//改变文件的位置for (int i = 0; i < cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].cur_file_size; i++) //注意这里的减一{cur_user.next->direct[index].ufd[i].addr = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].addr;cur_user.next->direct[index].ufd[i].filename = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].filename;cur_user.next->direct[index].ufd[i].length = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].length;cur_user.next->direct[index].ufd[i].protect_code = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].protect_code;}cur_user.next->cur_user_direct_size--; //目录数量减1cout << "删除目录成功" << endl;return 1;}

DIR函数(显示当前目录)

循环找到当前文件夹判断是否在根目录是则循环输出文件名,否则输出文件相关信息

 

int DIR()//显示当前地址下的内容{int index;for (index = 0; index < cur_user.next->cur_user_direct_size; index++){if (path == cur_user.next->direct[index].directname){break;}}if (path == ""){cout << " 目录名" << endl;for (int i = 0; i < cur_user.next->cur_user_direct_size; i++){cout << " " << cur_user.next->direct[i].directname << endl;}}else{cout << "\t文件名\t文件保护码\t文件长度\t文件起始盘块号\t\t创建日期" << endl;for (int i = 0; i < cur_user.next->direct[index].cur_file_size; i++){cout << "\t" << cur_user.next->direct[index].ufd[i].filename << "\t" << cur_user.next->direct[index].ufd[i].protect_code << "\t" << "\t" <<cur_user.next->direct[index].ufd[i].length << "\t" << "\t" << cur_user.next->direct[index].ufd[i].addr << "\t" << "\t" << "\t" << cur_user.next->direct[index].ufd[i].time << endl;}}return 1;}

 

SET函数(设置文件保护码)

循环找到文件夹循环找文件判断文件是否已打开(打开不可设置保护码)更改保护码

 

int SET(string name,int protectcode)//设置文件保护码{int index;for (index = 0; index < cur_user.next->cur_user_direct_size; index++)//找到文件夹的位置{if (path == cur_user.next->direct[index].directname){break;}}int i = 0;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//找文件{if (name == cur_user.next->direct[index].ufd[i].filename)break;}if (i >= cur_user.next->direct[index].cur_file_size){cout << "该用户没有这个文件" << endl;return 0;}int j;for (j = 0; i < cur_opentable->cur_openfilesize; j++){if (cur_opentable->uof[j].filename == path + "/" + name)break;}if (j < cur_opentable->cur_openfilesize){cout << "请先关闭该文件" << endl;return 0;}cur_user.next->direct[index].ufd[i].protect_code = protectcode;return 1;}

 

fatused函数(输出块的状态)

类似位示图

 

//输出块的状态int fatused(){for (int i = 0; i < BLOCK_NUM; i++)//判断是否有空闲块 磁盘块数量64 每个块大小512{// cout << fat[i].used << " ";printf("%d ",fat[i].used);if(i % 8 == 0){cout << endl;}}cout << endl;return 1;}

 

问题总结和心得

熟练运用指针和结构体构建文件整体结构

块号位示图问题

删除文件后,该文件的块号状态应置为空闲将最后一块的块号状态置0最后一个块号的内容替换到删除的位置如果已经是最后一块,则直接删除并置为空闲

当前用户问题

当登录后,此用户为当前用户找到当前用户的文件数组

文件读写问题

文件被打开时才可进行读写操作通过文件保护码,判断文件是否可写可读(2:可读可写;0:不可读;其他:可读)

文件保护问题

当文件被打开时不可删除当文件被打开时不可修改文件保护码可读可写保护追加信息写入问题每个用户只能访问自己的文件夹

删除文件问题

先进入对应文件夹找到要删除的文件判断文件是否被打开删除文件信息清空文件所占用的空间

代码整合

#include <iostream>#include <string>#include <malloc.h>#include<time.h>using namespace std;#define BLOCK_SIZE 512 //每一个磁盘块的大小#define BLOCK_NUM 64 //磁盘块数量#define MAX_FILE_NUM16 //每个文件夹的最大文件数#define MAX_FOLDER_NUM 16 //每个用户可以拥有的最大文件夹数#define MAX_OPEN_FILE_NUM 16 //最大同时打开文件数#define MAX_USER_NUM16 //最大用户数struct MFD//用户数据结构{string username;//用户名string password;//密码struct USER_UFD *next;//指向用户文件的指针};struct UFD//文件夹数据结构 {struct file_message//文件数据结构{string filename;//文件名int protect_code;//文件保护码int length;//文件长度int addr;//文件起始地址string time;//日期时间,格式为yyyymmdd hhmmss int used;//是否被占用 0:空闲 1:占用}ufd[MAX_FILE_NUM];//一个文件夹最对可以有16个文件string directname;//文件夹名字int cur_file_size = 0;//当前该文件夹含有的文件数量};struct UOF//打开文件数据结构{struct uof{string filename;//文件名字int pointer;//文件长度int protect_code;//文件保护码 默认2 2为可读可写 0为不可读 其余数字不可写int addr;//文件起始地址}uof[MAX_OPEN_FILE_NUM];//最多可以同时打开16个文int cur_openfilesize = 0;//当前打开的文件数量};struct fat//块号{int next = -1;//存放下一页的块号,无为-1int used = 0; //used存在三种状态,1:被占用 0:空闲}fat[BLOCK_NUM];//最大为64struct USER_UFD//用户文件数据结构{struct UFD direct[MAX_FOLDER_NUM];//一个用户最多可以有16个文件夹int cur_user_direct_size = 0;//当前拥有的文件夹数量};int mark = 1;struct USER_UFD cur_user_all_direct_array[MAX_USER_NUM];//用户文件数组 16struct MFD cur_user;//当前用户struct UOF * cur_opentable;//指向打开文件数组的指针char *fdisk;//模拟磁盘指针struct UOF openfile[MAX_OPEN_FILE_NUM];//每一个用户对应一个文件打开表对象,16struct MFD mfd[MAX_USER_NUM]; //16个用户int cur_user_size = 0;//记录当前用户的人数string path;int REGISTER();//注册用户int LOGIN();//登录用户int CREATE(string name);//创建文件int DELETE(string name);//删除文件int OPEN(string name);//打开文件int WRITE(string name);//写文件int READ(string name);//读文件int CLOSE(string name);//关闭文件int CD();//更改当前目录int MKDIR(string name);//创建文件夹int DIR();//显示当前目录的子目录int SET(string name, int protectcode);//设置保护码void INPUT_OPERATION();//指令输入int REGISTER()//注册用户{cout << "请输入用户名:";string username;cin >> username;cout << "请输入密码:";string password;cin >> password;for (int i = 0; i < MAX_USER_NUM; i++)//最大可有16个用户{if (mfd[i].username == username){cout << "注册失败,该用户名已存在" << endl;return 0;}}//将用户信息存入用户结构体中mfd[cur_user_size].username = username;mfd[cur_user_size].password = password;cur_user_size++;cout << "注册成功" << endl;return 1;}int LOGIN()//用户登入{cout << "请输入用户名:";string username;cin >> username;cout << "请输入密码:";string password;cin >> password;int i;for (i = 0; i < cur_user_size; i++){if (mfd[i].username == username){if (mfd[i].password != password){cout << "密码错误" << endl;return 0;}else{break;}}}if (i == cur_user_size){cout << "没有此用户" << endl;return 0;}mfd[i].next = &(cur_user_all_direct_array[i]);//用户文件指向第i个用户数组cur_user = mfd[i];//登入后此为当前目录cur_user.next->cur_user_direct_size = mfd[i].next->cur_user_direct_size;//让当前用户找到所登入的用户文件cur_user_size++;//用户人数+1cur_opentable = &openfile[cur_user_size]; //指针指向文件打开表对象 每一个用户一个文件打开表对象,该表中最多存放16个文件夹cur_opentable->cur_openfilesize = 0;//设置当前打开的文件数为0path = "";//设置path在刚登入时为空return 1;}//查看用户表int LOOK(){int i;for (i = 0; i < cur_user_size; i++){cout << mfd[i].username << " ";//遍历现有的用户数,方便观察}printf("\n"); return 1;}string getCurrentTimeStr()//得到时间{time_t t = time(NULL);char ch[64] = {0};strftime(ch, sizeof(ch) - 1, "%Y-%m-%d %H:%M:%S", localtime(&t));return ch;}//创建文件int CREATE(string name){int index;if (path == ""){cout << "请先进入文件夹,再创建文件" << endl;return 0;}for (index = 0; index < cur_user.next->cur_user_direct_size; index++){if (path == cur_user.next->direct[index].directname)//如果path等于文件夹名{break;}}int i;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//循环当前文件夹的文件数{if (name == cur_user.next->direct[index].ufd[i].filename){break;//文件名重复跳出循环}}if (i < cur_user.next->direct[index].cur_file_size)//重复 i会小于文件数,无重复 则等于{cout << "文件名重复" << endl;return 0;}if (cur_user.next->direct[index].cur_file_size == MAX_OPEN_FILE_NUM){cout << "该文件夹文件已达到"<< MAX_OPEN_FILE_NUM << "个" << endl;return 0;}int j;for (j = 0; j < BLOCK_NUM; j++)//判断是否有空闲块 磁盘块数量64 每个块大小512{if (fat[j].used == 0){break;}}if (j >= BLOCK_NUM){cout << "磁盘没有空闲块了" << endl;return 0;}string tim=getCurrentTimeStr();cout << tim << endl;cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].time = tim;//创建时间cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].filename = name;//上面都通过了保存文件名cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].addr = j; //文件起始盘块号cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].length = 0;//未写入数据,长度为0cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].protect_code = 2; //表示可读可写//cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size].time = tim;//创建时间cur_user.next->direct[index].cur_file_size++;//用户文件数量加1 fat[j].used = 1;//此时已被占用return 1;}//删除文件int DELETE(string name, int mark){if (path == "" && mark == -1){cout << "请在文件夹中删除文件" << endl;return 0;}int index;if(mark != -1) //如果是被RMDIR函数调用,则当前path=""index = mark;elsefor (index = 0; index < cur_user.next->cur_user_direct_size; index++)//循环用户拥有的文件夹{if (path == cur_user.next->direct[index].directname)//找到文件夹后退出{break;}}int i;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//循环该文件夹的文件{if (cur_user.next->direct[index].ufd[i].filename == name)//找到文件后退出{break;}}if (i >= cur_user.next->direct[index].cur_file_size){cout << "没有该文件" << endl;return 0;}int j;for (j = 0; i < cur_opentable->cur_openfilesize; j++)//循环打开的文件,查看是否被打开{if (cur_opentable->uof[j].filename == name)break;}if (j < cur_opentable->cur_openfilesize){cout << "该文件已被打开,无法删除" << endl;return 0;}//更新当前用户目录下文件数组信息,就是将最后一个文件的信息替换到要删除的文件的位置//如果本身是最后一个文件,那么不需要替换,直接删除if(i == cur_user.next->direct[index].cur_file_size -1){fat[cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].addr].used = 0; cur_user.next->direct[index].cur_file_size--;//next为-1 说明没有下一页,此为最后一页int temp = fat[cur_user.next->direct[index].ufd[i].addr].next;while (temp != -1)//删除该文件的内存空间{fat[temp].used = 0;temp = fat[temp].next;}cout << "删除文件" << name << "成功" << endl;return 1;}else{cur_user.next->direct[index].ufd[i].filename = cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].filename;//先将该块置0fat[cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].addr].used = 0; cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].addr = cur_user.next->direct[index].ufd[i].addr;cur_user.next->direct[index].ufd[i].length = cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].length;cur_user.next->direct[index].ufd[i].protect_code = cur_user.next->direct[index].ufd[cur_user.next->direct[index].cur_file_size - 1].protect_code;cur_user.next->direct[index].cur_file_size--;//将该文件设置为占用fat[cur_user.next->direct[index].ufd[i].addr].used = 1;//next为-1 说明没有下一页,此为最后一页int temp = fat[cur_user.next->direct[index].ufd[i].addr].next;while (temp != -1)//删除该文件的内存空间{fat[temp].used = 0;temp = fat[temp].next;}cout << "删除文件" << name << "成功" << endl;return 1;}}int OPEN(string name)//打开文件{ if (path == ""){cout << "请在文件夹中打开文件" << endl;return 0;}string AllName = path +'/'+name;//设置该变量的原因是防止出现打开文件数组中存在文件夹名不同而文件同名的情况int index;for (index = 0; index < cur_user.next->cur_user_direct_size; index++)//循环当前用户的文件{if (path == cur_user.next->direct[index].directname){ break;}}int i = 0;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//循环文件数{if (name == cur_user.next->direct[index].ufd[i].filename)//找到同名文件 break;}if (i >= cur_user.next->direct[index].cur_file_size){cout << "没有该文件" << endl;return 0;}if (cur_opentable->cur_openfilesize == MAX_OPEN_FILE_NUM){cout << "文件打开数量已经达到最大值" << endl;return 0;}for (int j = 0; i < cur_opentable->cur_openfilesize; j++){if (cur_opentable->uof[i].filename == AllName)//在打开文件中找到相应文件夹中的文件{ cout << "该文件已经打开" << endl; return 0;}}int k;for (k = 0; k < cur_user.next->direct[index].cur_file_size; k++){if (cur_user.next->direct[index].ufd[k].filename == name)//找到相应文件夹中的文件 break;} //将该文件的信息加入到已打开的文件数组中cur_opentable->uof[cur_opentable->cur_openfilesize].filename = AllName;//在打开的文件数组中加入该文件cur_opentable->uof[cur_opentable->cur_openfilesize].protect_code = cur_user.next->direct[index].ufd[k].protect_code;//保护码cur_opentable->uof[cur_opentable->cur_openfilesize].pointer = cur_user.next->direct[index].ufd[k].length;cur_opentable->uof[cur_opentable->cur_openfilesize].addr = cur_user.next->direct[index].ufd[k].addr;//起始地址cur_opentable->cur_openfilesize++; //文件打开数量加1cout << "文件打开成功" <<endl;return k; //返回文件在文件打开表中的第几项}int CLOSE(string name)//关闭文件{int i;for (i = 0; i < cur_opentable->cur_openfilesize; i++){if (cur_opentable->uof[i].filename == path + '/' + name){break;}}if (i >= cur_opentable->cur_openfilesize){cout << "该文将未打开" << endl;return 0;}//更新当前用户打开文件数组信息,就是将最后一个打开文件的信息替换到要关闭的打开文件的位置cur_opentable->uof[i].filename = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].filename;cur_opentable->uof[i].pointer = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].pointer;cur_opentable->uof[i].protect_code = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].protect_code;cur_opentable->uof[i].addr = cur_opentable->uof[cur_opentable->cur_openfilesize - 1].addr;cur_opentable->cur_openfilesize--;cout << "文件关闭成功" << endl;return 1;}int WRITE(string name)//写入文件{int index; //标识当前目录在direct数组中第几个for (index = 0; index < cur_user.next->cur_user_direct_size; index++){if (path == cur_user.next->direct[index].directname)//在当前用户的文件夹中找到相应的文件{break;}}int i;//判读文件是否打开for (i = 0; i < cur_opentable->cur_openfilesize; i++){if (cur_opentable->uof[i].filename == path + '/' + name)//循环打开的文件break;}if (i >= cur_opentable->cur_openfilesize){cout << "文件没有打开, 无法写入" << endl;return -1;}int fd = i; //获取文件描述字//判断读文件的合法性if (cur_opentable->uof[fd].protect_code != 2){cout << "文件不可写" << endl;return -1;}else{string content;//字符串 存储输入的一行内容cin.ignore();//cin.ignore()函数是C++标准输入流(cin)中的一个方法。cin.ignore()函数中有两个参数,//分别为数值型的a 和 字符型的 ch ,即cin.ignore( a, ch )。它表示从输入流 cin 中提取//字符,提取的字符被忽略,不被使用。而每抛弃一个字符,它都要进行计数和比较字符:如果//计数值达到 a 或者被抛弃的字符是 ch ,则cin.ignore() 函数执行终止;否则,它继续等待。//如果默认不给参数的话,默认参数为cin.ignore(1, EOF),即把EOF前的1个字符清掉,没有遇//到EOF就清掉一个字符然后结束。cout << "请输入文件要写入的内容: " << endl;;getline(cin, content); //读入一整行内容int cin_len = content.length();//输入一行的长度int cin_p=0;//初值为0int last_block_res;//磁盘剩余空间的大小//追加写//找到该文件存放的最后一个磁盘块 int last_block = cur_opentable->uof[fd].addr;while (fat[last_block].next != -1){last_block = fat[last_block].next;}int temp;//保存当前所写的文件在用户文件目录表的第几项,为了后面修改文件的大小for (int k = 0; k < cur_user.next->direct[index].cur_file_size; k++){if (cur_user.next->direct[index].ufd[k].filename == name)//找到该文件{temp = k;break;}}//计算该文件存放的最后一个地址char * first;first = fdisk + last_block * BLOCK_SIZE + cur_opentable->uof[fd].pointer % BLOCK_SIZE;//计算最后一个磁盘块还有多少空间if(cur_opentable->uof[fd].pointer == 0)last_block_res = BLOCK_SIZE;else if(cur_opentable->uof[fd].pointer % BLOCK_SIZE == 0)last_block_res = 0;elselast_block_res = BLOCK_SIZE - (cur_opentable->uof[fd].pointer % BLOCK_SIZE);//首先填满最后一个磁盘块if(last_block_res){if(last_block_res <= cin_len)//当最后一个磁盘块的空间小于输入内容大小{for(int j=0;j<last_block_res;j++)first[j] = content[cin_p++];cin_len -= last_block_res;//计算还有多少字符没存入}else//当最后一个磁盘块的空间大于输入内容大小{for(int j=0;j<cin_len;j++)first[j] = content[cin_p++];cur_opentable->uof[fd].pointer = cur_opentable->uof[fd].pointer + cin_len; //更新文件打开表cur_user.next->direct[index].ufd[temp].length = cur_user.next->direct[index].ufd[temp].length + cin_len; //更新用户目录文件表cout << "文件写入成功,共写入" << cin_len << "字节" << endl;return 0;}}//计算还需要多少个磁盘块,判断空间是否足够int times = cin_len / BLOCK_SIZE;//向上取整 求存满块数int offset = cin_len % BLOCK_SIZE;//取余 未存满if (offset != 0)times++;//块数+1int unused_block_num = 0; //记录没有使用过的磁盘块的个数int flag = 0;for (int j = 0; j < BLOCK_NUM; j++){if (fat[j].used == 0){unused_block_num++;}}if(unused_block_num < times)//剩余的块不够写{cout<<"空间不足,写入内容失败!\n";return -1;}int next_block = fat[cur_opentable->uof[fd].addr].next; //记录块的起始地址的nextint first_unused_block; //记录第一个没有被使用过的磁盘for(int j=0;j<times;j++){for (int k = 0; k < BLOCK_NUM; k++){if (fat[k].used == 0){first_unused_block = k;break;}}fat[last_block].next = first_unused_block;last_block = first_unused_block;first = fdisk + last_block * BLOCK_SIZE;if(j!=times-1){for(int k = 0;k<BLOCK_SIZE;k++)first[k] = content[cin_p++];}else{for(int k=0;k<offset;k++)first[k] = content[cin_p++];}}cur_opentable->uof[fd].pointer = cur_opentable->uof[fd].pointer + cin_p; //更新文件打开表cur_user.next->direct[index].ufd[temp].length = cur_user.next->direct[index].ufd[temp].length + cin_p; //更新用户目录文件表cout << "文件写入成功,共写入" << cin_p << "字节" << endl;return 0;}}int READ(string name)//读文件{int index1; //标识当前目录在direct数组中第几个for (index1 = 0; index1 < cur_user.next->cur_user_direct_size; index1++){if (path == cur_user.next->direct[index1].directname)//找到文件夹{break;}}int a;for (a = 0; a < cur_user.next->direct[index1].cur_file_size; a++) //判断文件是否存在{if (cur_user.next->direct[index1].ufd[a].filename == name)//找文件break;}if (a >= cur_user.next->direct[index1].cur_file_size){cout << "没有这个文件" << endl;return 0;}int i;//判读文件是否打开for (i = 0; i < cur_opentable->cur_openfilesize; i++){if (cur_opentable->uof[i].filename == path + '/' + name)break;}if (i >= cur_opentable->cur_openfilesize){cout << "文件没有打开, 无法读取" << endl;return -1;}int fd = i; //获取文件描述字//判断读文件的合法性if (cur_opentable->uof[fd].protect_code == 0) //我们创建的文件都是默认可读可写的{cout << "文件不可读" << endl;return 0;}else{int len = cur_opentable->uof[fd].pointer; //文件的长度int block_num = len / BLOCK_SIZE; //磁盘的个数int offset = len % BLOCK_SIZE; //偏移量if (offset != 0)block_num++;//如果我用一个文件表示磁盘的引导块,用另一个文件表示磁盘的数据块,那么我们计算文件的起始位置就不用加上磁盘的引导块了吧//关于文件的存放文件,我们char *fdisk表示一整个磁盘,然后不同文件的内容存放在这个指针所指向的不同字符段char * first = fdisk + cur_opentable->uof[fd].addr * BLOCK_SIZE; //文件的起始地址 第0块起始地址为0 第1块起始地址为512char * buf = (char *)malloc(513 * sizeof(char)); //缓冲区 给指针申请513个char类型大小的空间 512个空间存放内容 第513个存\0cout << "文件的内容为 :" << endl;for (int k = 0; k < block_num; k++){if (k == block_num - 1) //则是最后一个磁盘块{int j;for (j = 0; j < len - k * BLOCK_SIZE; j++) //赋值文件剩余的字符,其实就是偏移量{buf[j] = first[j];}buf[j] = '\0';//\0结束printf("%s\n", buf); //输出文件的内容}else //不在最后一个磁盘块,也就是在其他已经读满的磁盘块{int j;for (j = 0; j < BLOCK_SIZE; j++)buf[j] = first[j]; //缓冲区读满就输出内容buf[j] = '\0';printf("%s", buf); //输出文件的内容int next_block = fat[cur_opentable->uof[fd].addr].next; //读完一个磁盘块后,在接着读下一个磁盘块first = fdisk + next_block * BLOCK_SIZE;}}cout << endl;free(buf); //释放缓冲区return 0;}}int CD()//更改当前目录{string temp_path;cin >> temp_path;if (temp_path == ".."){if(path == ""){cout << "已在根目录" << endl;}else{path = ""; }return 1;}int i;for (i = 0; i < cur_user.next->cur_user_direct_size; i++){if (temp_path == cur_user.next->direct[i].directname)break;}if (i >= cur_user.next->cur_user_direct_size){cout << "没有此目录" << endl;return 0;}path = temp_path;//path为该路径return 1;}int MKDIR(string name)//创建目录{if (cur_user.next->cur_user_direct_size == MAX_USER_NUM){cout << "用户目录数量已经达到最大值" << endl;return 0;}int i;for (i = 0; i < cur_user.next->cur_user_direct_size; i++){if (cur_user.next->direct[i].directname == name)break;}if (i < cur_user.next->cur_user_direct_size){cout << "该目录名已存在" << endl;return 0;}cur_user.next->direct[cur_user.next->cur_user_direct_size].directname = name;cur_user.next->direct[cur_user.next->cur_user_direct_size].cur_file_size = 0; //新创建的目录里面的文件个数为0cur_user.next->cur_user_direct_size++;cout << "创建目录成功" << endl;return 1;}int RMDIR(string name)//删除目录{if(path != ""){cout << "请先退出文件夹" << endl;return 0;}int index;//文件夹的位置for (index = 0; index < cur_user.next->cur_user_direct_size; index++)//先判断是否有该文件夹{if (name == cur_user.next->direct[index].directname)break;}for (int i = 0; i < cur_user.next->direct[index].cur_file_size; i++){for(int j=0;i<cur_opentable->cur_openfilesize;j++)if (name + '/' + cur_user.next->direct[index].ufd[i].filename == cur_opentable->uof[j].filename){cout << "请先关闭该文件夹的所有文件" << endl;return 0;}}//删除该文件夹的所有文件for (int i = 0; i < cur_user.next->direct[index].cur_file_size; i++){DELETE(cur_user.next->direct[index].ufd[i].filename, index);}//把最后一个文件的位置放到删除的位置cur_user.next->direct[index].cur_file_size = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].cur_file_size; //注意这里需要减一,由于本身结构的限制cur_user.next->direct[index].directname = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].directname;//改变文件的位置for (int i = 0; i < cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].cur_file_size; i++) //注意这里的减一{cur_user.next->direct[index].ufd[i].addr = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].addr;cur_user.next->direct[index].ufd[i].filename = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].filename;cur_user.next->direct[index].ufd[i].length = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].length;cur_user.next->direct[index].ufd[i].protect_code = cur_user.next->direct[cur_user.next->cur_user_direct_size - 1].ufd[i].protect_code;}cur_user.next->cur_user_direct_size--; //目录数量减1cout << "删除目录成功" << endl;return 1;}int DIR()//显示当前地址下的内容{int index;for (index = 0; index < cur_user.next->cur_user_direct_size; index++){if (path == cur_user.next->direct[index].directname){break;}}if (path == ""){cout << " 目录名" << endl;for (int i = 0; i < cur_user.next->cur_user_direct_size; i++){cout << " " << cur_user.next->direct[i].directname << endl;}}else{cout << "\t文件名\t文件保护码\t文件长度\t文件起始盘块号\t\t创建日期" << endl;for (int i = 0; i < cur_user.next->direct[index].cur_file_size; i++){cout << "\t" << cur_user.next->direct[index].ufd[i].filename << "\t" << cur_user.next->direct[index].ufd[i].protect_code << "\t" << "\t" <<cur_user.next->direct[index].ufd[i].length << "\t" << "\t" << cur_user.next->direct[index].ufd[i].addr << "\t" << "\t" << "\t" << cur_user.next->direct[index].ufd[i].time << endl;}}return 1;}int SET(string name,int protectcode)//设置文件保护码{int index;for (index = 0; index < cur_user.next->cur_user_direct_size; index++)//找到文件夹的位置{if (path == cur_user.next->direct[index].directname){break;}}int i = 0;for (i = 0; i < cur_user.next->direct[index].cur_file_size; i++)//找文件{if (name == cur_user.next->direct[index].ufd[i].filename)break;}if (i >= cur_user.next->direct[index].cur_file_size){cout << "该用户没有这个文件" << endl;return 0;}int j;for (j = 0; i < cur_opentable->cur_openfilesize; j++){if (cur_opentable->uof[j].filename == path + "/" + name)break;}if (j < cur_opentable->cur_openfilesize){cout << "请先关闭该文件" << endl;return 0;}cur_user.next->direct[index].ufd[i].protect_code = protectcode;return 1;}//输出块的状态int fatused(){for (int i = 0; i < BLOCK_NUM; i++)//判断是否有空闲块 磁盘块数量64 每个块大小512{// cout << fat[i].used << " ";printf("%d ",fat[i].used);if(i % 8 == 0){cout << endl;}}cout << endl;return 1;}void INPUT_OPERATION()//指令输入{if (cur_user.username == "")cout << "localhost :";elsecout << cur_user.username << "@localhost home/" << path << ":";string operaton;cin >> operaton;if (operaton == "login"){LOGIN();}else if (operaton == "create"){string filename;cin >> filename;CREATE(filename);}else if (operaton == "del"){string name;cin >> name;DELETE(name, -1);}else if (operaton == "open"){string name;cin >> name;OPEN(name);}else if (operaton == "close"){string name;cin >> name;CLOSE(name);}else if (operaton == "write"){string content;string name;cin >> name;WRITE(name);}else if (operaton == "read"){string name;cin >> name;READ(name);}else if (operaton == "exit"){exit(0);}else if (operaton == "cd"){CD();}else if (operaton == "dir"){DIR();}else if (operaton == "mkdir"){string name;cin >> name;MKDIR(name);}else if (operaton == "register"){REGISTER();}else if (operaton == "exit"){mark = 0;}else if (operaton == "set"){string name;int protextcode;cin >> name;cin >> protextcode;SET(name, protextcode);}else if (operaton == "rmdir"){string name;cin >> name;RMDIR(name);}else if (operaton == "look"){LOOK();}else if (operaton == "fatused"){fatused();}else{cout << "命令错误,请重新输入" << endl;}}int main(){cur_user.username = "";path = "";fdisk = (char *)malloc(1024 * 1024 * sizeof(int));//模拟硬盘指针//注册root用户并登录,方便调试代码mfd[cur_user_size].username = "root";mfd[cur_user_size].password = "123456";cur_user_size++;mfd[0].next = &(cur_user_all_direct_array[0]);cur_user = mfd[0];cur_user.next->cur_user_direct_size = mfd[0].next->cur_user_direct_size;cur_user_size++;cur_opentable = &openfile[cur_user_size]; //指针指向文件打开表对象cur_opentable->cur_openfilesize = 0;cout << "*******************欢迎使用二级文件系统*******************" << endl;cout << " 命令格式 说明 " << endl;cout << " register 注册用户 " << endl;cout << " login 登录 " << endl;cout << " cd 目录名 更改当前目录 " << endl;cout << " mkdir 目录名 创建子目录 " << endl;cout << " rmdir 目录名 删除子目录 " << endl;cout << " dir 显示当前目录的子目录 " << endl;cout << " create 文件名 创建文件 " << endl;cout << " del 文件名 删除文件 " << endl;cout << " open 文件名 打开文件 " << endl;cout << " close 关闭文件 " << endl;cout << " read 文件名 读文件 " << endl;cout << " write 文件名 写文件 " << endl;cout << " set 文件名 文件保护码 设置文件保护码 " << endl;cout << " exit 退出系统 " << endl;cout << " look 查看用户 " << endl;cout << " fatused 查看块 " << endl;while (mark)INPUT_OPERATION();free(fdisk);return 1;}

此文章为学习记录^_^ 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。