可以看到文件命令是仿照Linux的,但是也就仿了一点点。所有代码都在一个cpp文件中(也没想到会写这么多,就没分开写了),代码总行数1800行左右,代码注释都是交给星火大模型弄的(老师要求要有详细注释,1800行太多啦,时间又赶,就交给人工智能啦),看了一下注释的基本没问题。好了下面是正文。
--------------
目录
1.概述
文件管理作为操作系统的一大基本功能,是实现程序和数据等信息存储的主要方式,因此文件管理系统也称为信息资源管理系统。文件管理要解决的问题是向用户提供一种简单便捷、统一的存取和管理信息的方法,同时要保证信息的安全性和共享性。本篇设计说明将通过使用C++语言结合Visual Studio 2019开发平台实现对文件管理系统的模拟,试图模拟出符合逻辑、拥有文件系统各项基本功能的系统。
2.预备知识
2.1文件管理的主要功能
文件管理的主要功能分为文件存储管理、目录管理、文件的读写管理、文件的存取管理。
2.1.1文件存储空间的管理
一般而言,系统文件和用户文件放在可随机存取的磁盘上。对于用户而言没有经过任何管理的文件寻找和使用起来都很不便捷,十分低效。因而,需要有文件系统对许多文件以及文件的存储空间进行统一管理。主要任务就是为每个文件分配足够的存储空间,提高存储空间的利用率,提高文件的工作速度。
2.1.2目录管理
目录管理是为了用户能方便的找到所需文件,也能便于用户对文件的各种分类管理,通常会由系统为每个文件建立一个目录项。目录项包含文件名、文件属性、文件的物理位置等信息。
2.1.3文件的读写管理
读写作为文件的基本操作,能够根据用户的需求读取磁盘数据或向磁盘写入数据。在读操作中,用户需要提供文件名,文件系统通过检索文件目录找到该文件,并获取文件所在的物理位置;在写操作中,用户可以在目录下创建文件并写入信息,文件系统为该文件创建目录项,同时分配存储空间,保存物理位置、文件名的信息等。
2.1.4文件的存取控制
为保证文件内信息的安全性和共享性,文件系统必须严格控制文件的存取过程。这涉及到文件的权限管理。在Linux系统中主要有读、写、执行权限,Windows系统中的权限更为复杂,且各用户之间权限交叉程度大。
2.2文件属性
文件包含两部分内容:一是文件所包含的数据;二是文件所包含的自身说明信息,即属性。文件属性主要有以下几种:
(1)文件名。
(2)文件内部标识符。也就是一个编号,是系统内为每个文件创建的唯一标识符。
(3)文件的物理位置。
(4)文件的拥有者。
(5)文件的存取控制。这决定了系统中各种用户对该文件的权限。
(6)文件的类型。
(7)文件的长度。
(8)文件时间。如创建时间,最后一次修改时间等。
2.3文件操作
文件操作指文件向用户提供的各种接口。主要分为两大类:一是对文件记录的操作;二是对文件自身的操作。
2.3.1对文件记录的操作
(1)检索记录。
(2)插入记录。
(3)修改记录。
(4)删除记录。
2.3.2对文件自身的操作
(1)创建文件。创建文件时,系统要为其分配存储空间,并建立一个目录项。
(2)删除文件。删除时,系统将该文件的目录项置空,然后回收存储空间。
(3)读文件。
(4)写文件。
(5)设置文件的读/写位置。对文件进行读/写操作之前,需要对文件的读/写
(6)截断文件。如果一个文件的内容已经没用,虽然可以先删除文件在建立一个新的文件,但如果文件名及其属性并没有发生变化,也可以截断文件。即将文件的长度设为0,或者放弃原有的文件内容。
(7)打开文件。
(8)关闭文件。
(9)获取文件属性。
(10)设置文件的属性。用户可以改变文件的存取控制权限等。
2.4文件控制块(FCB)
为了能够对文件进行正确的存取,必须为文件设置一种用于描述和控制文件的数据结构——文件控制块(File Control Block,FCB)。文件控制块的有序集合即为文件目录,文件控制块就是其中的目录项。该数据结构包含以下内容:
(1)文件名。
(2)文件物理位置。
(3)文件逻辑位置。
(4)文件的存取权限。
(5)核准用户的存取权限。
(6)一般用户的存取权限。
(7)文件的建立日期和时间。
(8)文件的修改日期和时间。
(9)当前使用信息。包括当前已打开文件的进程数、文件是否被进程锁住等。
2.5目录
目录的存在主要是方便通过用户给的文件名找到文件。
2.5.1目录的功能
目录的功能如下:
(1)实现按名存取。用户只需要给出文件名,即可对文件进行各种操作。
(2)提高检索速度。合理地组织目录结构,加快文件检索速度。
(3)允许文件同名。便于用户能够按照自身的习惯来命名和使用文件。
(4)文件共享。一个文件能够被多个用户使用。这要求文件系统有合理的文件权限管理。
2.5.2目录的操作
目录有以下操作:
(1)目录创建。目录就是多个文件控制块的集合,通常以文件的形式存储在外部存储器上,目录创建就是在外存上建立一个目录文件用以存储文件的FCB。
(2)目录删除。
(3)目录检索。当用户按名存取文件时,文件系统能够通过对目录进行检索找到对应文件。
(4)目录的打开与关闭。
2.5.3树形目录
在树形目录中,有一个主目录和许多分目录,分目录不但可以包括文件,还可以包含下一级目录,这样扩展下去就形成了多级层次目录,这样也方便地制定保护文件的存取权限。主目录是树的根节点,文件时树的叶子节点,其他分目录是树的分支节点。在树形目录中通过路径名来访问文件,在该通路上的所有文件名和目录名用“\”连接起来,构成该文件的路径名。通常树形目录会为每个用户设置一个当前目录,也称工作目录。树形目录能够方便用户查找文件,又可以把不同类型的文件进行分类,同时,只要在不同的分目录中,文件命名可以相同。
3.系统设计
为构建符合逻辑,拥有各项文件系统基本功能的系统,我仿照linux中对文件管理的操作,在系统设计方面提出了四大模块:用户管理、内存管理、文件管理、命令函数。它们分别实现对用户的简单管理,对内存的简单管理、对文件的较复杂的管理和对系统的操作命令。
3.1用户的简单管理
在这一模块中,定义了一个用户类(User),用户的属性只有简单的两个,即用户名和密码。用户的操作有获取用户名、获取密码、设置用户名、设置密码。为实现对用户的简单管理,我在此基础上又新增加了一个类专门用来管理用户信息,命名为UserList,实现添加用户,删除用户,查找用户等功能。这两个类的设计如下:
// 用户类 class User { private: string name; string passwd; public: User() {} User(string name_c, string passwd_c) { this->name = name_c; this->passwd = passwd_c; } ~User() {} void operator () (string name, string passwd) { this->name = name; this->passwd = passwd; } string GetName() { return this->name; } string GetPasswd() { return this->passwd; } void SetName(string name) { this->name = name; } void SetPasswd(string passwd) { this->passwd = passwd; } }; // 实现简单的用户管理 class UserList { public: bool AddUser(User u); // 添加用户 bool DelUser(User u); // 删除用户 bool DelUser(string name); short FindUser(User u); // 查找用户,找到则返回所在用户表中的位置 short FindUser(string name); // 查找用户,找到则返回所在用户表中的位置 void ViewUser(); // 查看用户 bool Signin(string name, string pw); // 用户登录 User GetUser(string name); private: bool FindUserByPw(string passwd, int i); // 密码对比 vector<User> users; // 用户表 static short n; // 记录UserList实例化数 };
3.2简单的内存管理
在内存管理这一模块中,我是以向系统申请一块能够存储1024个int整形数组,通过对数组中的值赋0或者1来表示文件在系统中的位置和大小,以此构建一个简单的虚拟的内存管理。其中0表示该内存为空,1表示该内存已占用。值得注意的是用户的创建不占用内存。内存管理类命名为Location,有申请内存、获取地址和回收内存的功能,具体类设计如下:
constexpr auto MAX_MEMORY = 1024; // 内存管理 class Location { private: static int maxLocation[MAX_MEMORY]; int location = 0; public: Location():location(0) {} Location(int size); bool SetLocation(int size); // 申请内存 int GetLocation() { return location; } // 获取地址 void Recycle(int size); // 回收内存 };
3.3较复杂的文件管理
在这一模块中,为了能够较规范的实现文件管理,我定义了3个类:FCB、文件(File)、目录(Directory)。权限控制仿照Linux给出了3种权限,分别是:读(read)、写(write)、执行(execute),用整型表示为1、2、4。
3.3.1 FCB类
FCB的主要功能是存储除了文件内容外的文件所有信息,以及能够对已修改的文件进行信息更新,同时还提供了信息视图。
在FCB中,有如下属性:
- 文件名(fname);
- 文件位置(location);
- 文件大小(size);
- 属主用户(mUser);
- 主用户权限(masterUser);
- 其他用户权限(otherUser);
- 文件建立时间(createTime);
- 文件修改时间(alterTime)。
功能有:
- 创建FCB(SetFCB)
- 查看FCB视图(ViewFCB)
- 更新命名(UpdateName)
- 更新文件内容大小(UpdateFCSize)
- 更新权限(UpdateRight)
- 更新修改时间(UpdateaTime)
- 获取文件名(GetName)
- 获取内容大小(GetFCSize)
- 获取主用户信息(GetmUser)
具体类设计如下:
class FCB { private: string fname; // 文件名 Location location; // 文件位置 int size = 0; // 文件大小 User mUser; // 属主用户 int masterUser = 0; // 主用户权限 int otherUser = 0; // 其他用户权限 string createTime; // 文件建立时间 string alterTime; // 文件修改时间 public: FCB() {} FCB(string name, User user); void SetFCB(string name, User user); // 创建FCB void ViewFCB(); // 查看FCB视图 void UpdateName(string name); // 更新命名 void UpdateFCSize(int size); // 更新文件内容大小 void UpdateRight(int m , int o); // 更新权限 void UpdateaTime(); // 更新修改时间 string GetName(); // 获取文件名 int GetFCSize(); // 获取内容大小 User GetmUser(); // 获取主用户信息 };
3.3.2文件(File)类
该类主要功能是实现文件的创建,文件内容的增删改查,文件权限的修改等,每一个实例对象都包含一个FCB,换句话说FCB是保存在文件中的。文件的内容用一个string类型变量存储。
具体类设计如下:
class File { private: string fcontent; FCB fcb; public: File(); bool CreateFile(string fname, User user); // 创建文件 void View() { fcb.ViewFCB(); } // 文件视图 void WriteFileC(string content); // 增 void DelFileC(); // 删 void AlterFileC(string content); // 改 void ReadFileC(); // 查 void ExecuteFile(); // 执行 void AlterFileR(int mright, int oright ); // 修改权限 string GetFName(); // 获取命名 User GetmUser(); // 获取属主用户 void AlterFName(string name); // 更改文件名 };
3.3.3目录(Directory)类
目录类需要实现的功能是存储目录的所有信息,包含目录下存在的目录和文件,以此实现树形目录结构的管理,还有创建、添加、删除等各项功能。值得注意的是目录类中所包含的目录和文件是以目录名和文件名存储在一个string的向量中的,在通过路径查找目录或者文件时,会通过存储在向量中的文件名和目录名查找该目录下是否存在,不存储在则显示无此文件或目录。该类主要是提供有关目录的基础操作。
目录类的具体定义如下:
class Directory { private: string dname; int cnum; // 记录目录数量 int fnum; // 记录文件数量 int size; // 目录大小 int masterUser = 0; // 主用户权限 int otherUser = 0; // 其他用户权限 string createTime; // 创建时间 string alterTime; // 修改时间 Location location; // 在虚拟内存中的位置 User duser; // 目录所属用户 string fcontent; // 父目录 vector<string> contents; // 子目录 vector<string> files; // 子文件 public: Directory(); Directory(string name, User user); ~Directory(); bool Create(string name, User user); // 创建目录 void Delete(); // 删除目录 void AlterDName(string name); // 更改目录名 bool AlterDRight(int m, int o); // 更改目录权限 void Open(); // 查看目录下包含的目录和文件,对应ls操作 bool AddContent(const string& content); // 向目录中添加目录(名) bool DelContent(const string& content); // 向目录中删除目录(名) bool AddFile(string& filename); // 向目录中添加文件(名) bool AlterFileName(string& oldName, string& newName, File& file); // 在目录中更改包含文件的文件名 bool AlterContentName(string& oldName, string& newName, Directory& content); // 在目录汇总更改包含目录的目录名 bool DelFile(string name); // 向目录中删除文件(名) int FindFile(string name); // 查找包含文件 int FindContent(string name); // 查找包含目录 string GetDName(); // 获取目录名 string GetFName(int i); // 获取文件名 string GetUName(); // 获取主用户名 int GetMRight(); // 获取主用户权限 int GetORight(); // 获取其他用户权限 vector<string> GetFiles(); // 获取包含文件向量 vector<string> GetContents(); // 获取包含目录向量 void Recycle(); // 回收目录所占用空间 void View(); // 目录视图 };
3.4命令函数
对该文件系统的命令操作以仿照Linux为主,提供了ls、useradd、su等经典操作。各函数声明如下:
// 命令 bool ls(); // 查看当前目录 bool useradd(); // 添加用户 bool su(string name); // 登录用户 bool userdel(string name); // 删除用户 bool useralt(); // 修改用户信息 bool touch(string name); // 创建文件 bool cat(string name); // 读取文件 bool echo(string name); // 打开并编辑文件 bool rm(string name); // 删除文件 bool mkdir(string name); // 创建目录 bool mvdir(string name); // 删除目录 bool cd(string path); // 打开目录 void ls_l(); // 查看当前目录详细信息 bool alter_f(string name); // 更改文件名 bool alter_d(string name); // 更改目录名 bool chmod_f(string name); // 更改文件的权限 bool chmod_d(string name); // 更改目录的权限 void ls_a(); // 查看所有目录和文件的详细信息 void help(); // 获取所有命令信息
3.5其他函数申明
这里主要包括本地时间获取函数、控制台输出美化函数、分割字符创等函数,具体声明如下:
// 获取控制台句柄 const HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // 获取当地时间 string GetTime(); // 隐藏控制台光标 void HideConsoleCursor(); // 显示控制台光标 void ShowConsoleCursor(); // uFore: 前景色,uBack: 背景色 void SetColor(UINT uFore, UINT uBack); // 指定前景色和背景色,缓慢输出 void ccout(const char* c, UINT uFore = 7, UINT uBack = 0, UINT sleeptime = 0); // 输出命令行头 void PutHeadInCommandLine(); // 权限检查 int RightCheck(); // 分割字符串 vector<string> split(string str, string pattern);
4.系统实现
引入的头文件:
#include <iostream> #include <string> // I love string!!!! #include <time.h> #include <vector> #include <windows.h> using namespace std;
4.1用户管理
用户管理代码实现如下:
// Class: UserList short UserList::n = 0; // 添加用户 bool UserList::AddUser(User u) { int i = FindUser(u); // 查找用户名 if (i == -1) // 如果用户不存在,则添加用户 { users.push_back(u); // 将用户添加到用户列表中 n++; // 用户数量加1 return true; // 返回添加成功 } return false; // 返回添加失败,用户已存在 } // 删除用户 bool UserList::DelUser(User u) { short i = FindUser(u); // 查找用户名 if (i != -1) // 如果用户存在 { for (vector<User>::iterator it = users.begin(); it != users.end(); it++) // 遍历用户列表 { if ((*it).GetName() == u.GetName()) // 如果找到匹配的用户 { users.erase(it); // 从用户列表中删除该用户 return true; // 返回删除成功 break; } } n--; // 用户数量减1 return true; // 返回删除成功 } return false; // 返回删除失败,用户不存在 } bool UserList::DelUser(string name) { short i = FindUser(name); // 查找用户名 if (i != -1) // 如果用户存在 { for (vector<User>::iterator it = users.begin(); it != users.end(); it++) // 遍历用户列表 { if ((*it).GetName() == name) // 如果找到匹配的用户 { users.erase(it); // 从用户列表中删除该用户 return true; // 返回删除成功 break; } } n--; // 用户数量减1 return true; // 返回删除成功 } return false; // 返回删除失败,用户不存在 } // 查找用户,找到则返回所在用户表中的位置 short UserList::FindUser(User u) { int i = 0; for (vector<User>::iterator it = users.begin(); it != users.end(); it++) // 遍历用户列表 { if ((*it).GetName() == u.GetName()) // 如果找到匹配的用户 { return i; // 返回用户在列表中的位置 } i++; // 继续查找下一个用户 } return -1; // 返回-1,表示未找到匹配的用户 } // 查找用户,找到则返回所在用户表中的位置 short UserList::FindUser(string name) { int i = 0; for (vector<User>::iterator it = users.begin(); it != users.end(); it++) // 遍历用户列表 { if ((*it).GetName() == name) // 如果找到匹配的用户 { return i; // 返回用户在列表中的位置 } i++; // 继续查找下一个用户 } return -1; // 返回-1,表示未找到匹配的用户 } // 密码对比 bool UserList::FindUserByPw(string passwd, int i) { if (n == 0) // 如果用户列表为空 { return false; // 返回false,表示未找到匹配的用户 } for (i; i < n; i++) // 遍历用户列表 { if (users[i].GetPasswd().compare(passwd) == 0) // 如果找到匹配的用户 { return true; // 返回true,表示找到了匹配的用户 } } return false; // 返回false,表示未找到匹配的用户 } // 查看用户 void UserList::ViewUser() { for (int i = 0; i < n; i++) // 遍历用户列表 { cout << users[i].GetName() << "\t"; // 输出用户名称和制表符 cout << endl; // 换行 } } // 用户登录 bool UserList::Signin(string name, string pw) { int i = FindUser(name); // 查找用户名 if (i != -1) // 如果用户存在 { if (users[i].GetPasswd().compare(pw) == 0) // 如果密码匹配 { *curuser = users[i]; // 将当前用户设置为登录的用户 return true; // 返回登录成功 } } return false; // 返回登录失败,用户名或密码错误 } // 获取用户列表 User UserList::GetUser(string name) { return users[FindUser(name)]; // 返回指定用户名的用户对象 }
4.2内存管理
内存管理实现代码如下:
// 初始化内存 int Location::maxLocation[MAX_MEMORY] = { 0 }; // 定义一个静态数组,用于存储内存状态,0表示未使用,1表示已使用 // 构造函数,同SetLocation Location::Location(int size) { int i = 0; while (1) { for (i; i < MAX_MEMORY; i++) // 遍历数组,找到第一个未使用的内存位置 { if (maxLocation[i] == 0) { break; } } int j = i; int n = 0; for (j; j < i + size; j++) // 计算需要申请的内存大小 { if (j < MAX_MEMORY && maxLocation[j] == 0) { n++; } } if (n == size) // 如果需要申请的内存大小与实际可用内存大小相等,则分配内存并更新数组状态 { location = i; for (int k = i; k < i + size; k++) { maxLocation[k] = 1; } break; } } } // 申请内存 bool Location::SetLocation(int size) { int i = 0; while (1) { for (i; i < MAX_MEMORY; i++) // 遍历数组,找到第一个未使用的内存位置 { if (maxLocation[i] == 0) { break; } } int j = i; int n = 0; for (j; j < i + size; j++) // 计算需要申请的内存大小 { if (j < MAX_MEMORY && maxLocation[j] == 0) { n++; } } if (n == size) // 如果需要申请的内存大小与实际可用内存大小相等,则分配内存并更新数组状态,返回true { location = i; for (int k = i; k < i + size; k++) { maxLocation[k] = 1; } return true; } i = j; } return false; // 如果无法满足需求,返回false } // 回收内存 void Location::Recycle(int size) { int i = location; for (i; i < size + location; i++) // 将申请的内存标记为未使用 { maxLocation[i] = 0; } location = 0; // 重置当前内存位置为0 }
4.3文件管理
FCB类实现代码如下:
// 构造函数 FCB::FCB(string name, User user) { fname = name; // 设置文件名 location.SetLocation(name.length()); // 设置文件位置 size = name.length(); // 设置文件大小 mUser = user; // 设置属主用户 masterUser = 7; // 设置主用户权限为7 otherUser = 1; // 设置其他用户权限为1 createTime = GetTime(); // 设置文件建立时间 alterTime = ""; // 初始化文件修改时间为空字符串 } // 创建FCB void FCB::SetFCB(string name, User user) { fname = name; // 设置文件名 location.SetLocation(name.length()); // 设置文件位置 size = name.length(); // 设置文件大小 mUser = user; // 设置属主用户 masterUser = 7; // 设置主用户权限为7 otherUser = 1; // 设置其他用户权限为1 createTime = GetTime(); // 设置文件建立时间 alterTime = ""; // 初始化文件修改时间为空字符串 } // 查看FCB视图 void FCB::ViewFCB() { // 拼接文件信息字符串 string s = ""; s += fname; // 添加文件名 s.append("|"); s += to_string(location.GetLocation()); // 添加文件位置 s.append("|"); s += to_string(size); // 添加文件大小 s.append("|"); s += mUser.GetName(); // 添加属主用户名称 s.append("|"); s += to_string(masterUser); // 添加主用户权限 s.append("|"); s += to_string(otherUser); // 添加其他用户权限 s.append("|"); s += createTime; // 添加文件建立时间 s.append("|"); s += alterTime; // 添加文件修改时间 // 输出文件信息字符串 ccout(s.c_str()); cout << endl; } // 更新命名 void FCB::UpdateName(string name) { this->fname = name; // 更新文件名 } // 更新文件内容大小 void FCB::UpdateFCSize(int size) { this->size = size + fname.length(); // 更新文件大小 this->location.Recycle(this->size); // 回收旧的文件位置空间 this->location.SetLocation(this->size); // 设置新的文件位置 } // 更新权限 void FCB::UpdateRight(int m, int o) { this->masterUser = m; // 更新主用户权限 this->otherUser = o; // 更新其他用户权限 } // 更新修改时间 void FCB::UpdateaTime() { this->alterTime = GetTime(); // 更新文件修改时间 } // 获取文件名 string FCB::GetName() { return fname; // 返回文件名 } // 获取内容大小 int FCB::GetFCSize() { return size - fname.length(); // 返回文件内容大小(不包括文件名) } // 获取主用户信息 User FCB::GetmUser() { return this->mUser; // 返回属主用户对象 }
文件File类的实现代码如下:
// Class: File File::File() {} // 创建文件 bool File::CreateFile(string fname, User user) { fcb.SetFCB(fname, user); // 设置文件控制块(FCB)的属性,包括文件名和属主用户 return true; // 返回创建成功的标志 } // 增加文件内容 void File::WriteFileC(string content) { fcontent.append(content); // 将传入的内容追加到文件内容中 fcb.UpdateaTime(); // 更新文件的修改时间 fcb.UpdateFCSize(content.length()); // 更新文件的大小(不包括文件名) } // 删除文件内容 void File::DelFileC() { fcontent = ""; // 清空文件内容 fcb.UpdateFCSize(0); // 更新文件大小为0 fcb.UpdateaTime(); // 更新文件的修改时间 } // 更改文件内容 void File::AlterFileC(string content) { DelFileC(); // 先删除原有内容 WriteFileC(content); // 再写入新的内容 } // 查看文件内容 void File::ReadFileC() { ccout(fcontent.c_str()); // 输出文件内容 } // 执行文件 void File::ExecuteFile() { cout << fcb.GetName() << " are executing" << endl; // 输出正在执行的文件名 // _sleep(1000); // 暂停1秒(可选) cout << "end!" << endl; // 输出执行结束的信息 } // 修改权限 void File::AlterFileR(int mright, int oright) { fcb.UpdateRight(mright, oright); // 更新文件的读写权限 } // 获取命名 string File::GetFName() { return fcb.GetName(); // 返回文件名 } // 获取属主用户 User File::GetmUser() { return fcb.GetmUser(); // 返回属主用户对象 } // 更改文件名 void File::AlterFName(string name) { fcb.UpdateName(name); // 更新文件名 }
目录(Directory)类的实现代码如下:
// 类:Directory // 构造函数 Directory::Directory() { dname = ""; // 目录名 cnum = 0; // 记录目录数量 fnum = 0; // 记录文件数量 size = 0; // 目录大小 masterUser = 0; // 主用户权限 otherUser = 0; // 其他用户权限 createTime = ""; // 创建时间 alterTime = ""; // 修改时间 location.SetLocation(size); // 在虚拟内存中的位置 duser = User(); // 目录所属用户 fcontent = ""; // 父目录 } // 带参数的构造函数 Directory::Directory(string name, User user) { dname = name; cnum = 0; fnum = 0; size = name.length(); masterUser = 7; otherUser = 5; createTime = GetTime(); alterTime = ""; location.SetLocation(size); duser = user; if (curdirectory != nullptr) { fcontent = curdirectory->GetDName(); } } // 析构函数 Directory::~Directory() { // 释放资源 } // 创建目录 bool Directory::Create(string name, User user) { bool b = location.SetLocation(name.length()); if (b) { dname = name; cnum = 0; fnum = 0; size = name.length(); masterUser = 7; otherUser = 5; createTime = GetTime(); alterTime = ""; duser = user; if (curdirectory != nullptr) { fcontent = curdirectory->GetDName(); } return true; } else { return false; } } // 删除目录 void Directory::Delete() { location.Recycle(size); dname = ""; cnum = 0; fnum = 0; size = 0; masterUser = 0; otherUser = 0; createTime = ""; alterTime = ""; contents.clear(); files.clear(); } // 更改目录名 void Directory::AlterDName(string name) { dname = name; location.Recycle(size); size = name.length(); location.SetLocation(size); } // 向目录中添加目录(名) bool Directory::AddContent(const string& content) { for (int i = 0; i < cnum; i++) { if (contents[i].compare(content) == 0) { return false; } } contents.push_back(content); cnum++; return true; } // 向目录中添加文件(名) bool Directory::AddFile(string& filename) { if (FindFile(filename) != -1) { return false; } files.push_back(filename); fnum++; return true; } // 更改目录权限 bool Directory::AlterDRight(int m, int o) { this->masterUser = m; this->otherUser = o; return true; } // 查看目录下包含的目录名和文件名,对应ls操作 void Directory::Open() { for (vector<string>::iterator it = contents.begin(); it != contents.end(); ++it) { ccout("&", 6, 0); ccout((*it).c_str(), 6, 0); ccout(" "); } for (vector<string>::iterator it = files.begin(); it != files.end(); ++it) { cout << *it << " "; } cout << endl; } // 向目录中添加文件(名) bool Directory::AlterFileName(string& oldName, string& newName, File& file) { int s = FindFile(oldName); if (s != -1) { files[s] = newName; file.AlterFName(newName); return true; } else return false; } // 在目录中更改包含文件的文件名 bool Directory::AlterFileName(string& oldName, string& newName, File& file) { int s = FindFile(oldName); // 查找旧文件名在文件列表中的索引 if (s != -1) // 如果找到了旧文件名 { files[s] = newName; // 将新文件名赋值给文件列表中对应的位置 file.AlterFName(newName); // 更新文件对象的名称 return true; // 返回成功标志 } else // 如果没有找到旧文件名 return false; // 返回失败标志 } // 在目录汇总更改包含的目录的目录名 bool Directory::AlterContentName(string& oldName, string& newName, Directory& content) { int s = FindContent(oldName); // 查找旧目录名在目录列表中的索引 if (s != -1) // 如果找到了旧目录名 { contents[s] = newName; // 将新目录名赋值给目录列表中对应的位置 content.AlterDName(newName); // 更新目录对象的名称 return true; // 返回成功标志 } else // 如果没有找到旧目录名 return false; // 返回失败标志 } // 向目录中删除文件(名) bool Directory::DelFile(string name) { for (vector<string>::iterator it = files.begin(); it != files.end(); it++) // 遍历文件列表 { if ((*it) == name) // 如果找到了要删除的文件名 { files.erase(it); // 从文件列表中删除该文件名 fnum--; // 更新文件数量 return true; // 返回成功标志 } } return false; // 如果没有找到要删除的文件名,返回失败标志 } // 查找包含文件 int Directory::FindFile(string name) { for (int i = 0; i < fnum; i++) // 遍历文件列表 { if (files[i].compare(name) == 0) // 如果找到了要查找的文件名 { return i; // 返回该文件名在文件列表中的索引 } } return -1; // 如果没有找到要查找的文件名,返回-1 } // 查找包含目录 int Directory::FindContent(string name) { for (int i = 0; i < cnum; i++) // 遍历目录列表 { if (contents[i].compare(name) == 0) // 如果找到了要查找的目录名 { return i; // 返回该目录名在目录列表中的索引 } } return -1; // 如果没有找到要查找的目录名,返回-1 } // 获取目录名 string Directory::GetDName() { return dname; // 返回目录名 } // 获取文件名 string Directory::GetFName(int i) { return this->files[i]; // 返回指定索引处的文件名 } // 获取主用户名 string Directory::GetUName() { return this->duser.GetName(); // 返回目录所属用户的用户名 } // 获取主用户权限 int Directory::GetMRight() { return this->masterUser; // 返回主用户权限 } // 获取其他用户权限 int Directory::GetORight() { return this->otherUser; // 返回其他用户权限 } // 获取包含文件向量 vector<string> Directory::GetFiles() { return files; // 返回包含文件的向量 } // 获取包含目录向量 vector<string> Directory::GetContents() { return contents; // 返回包含目录的向量 } // 回收目录所占用空间 void Directory::Recycle() { location.Recycle(size); // 回收目录所占用的内存空间 } // 目录视图 void Directory::View() { // 初始化字符串s,用于存储目录信息 string s = "&"; // 将目录名添加到字符串s中 s += dname; // 在字符串s中添加分隔符"|" s.append("|"); // 将目录在虚拟内存中的位置转换为字符串并添加到字符串s中 s += to_string(location.GetLocation()); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录大小转换为字符串并添加到字符串s中 s += to_string(size); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录包含的文件数量转换为字符串并添加到字符串s中 s += to_string(cnum); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录包含的文件数量转换为字符串并添加到字符串s中 s += to_string(fnum); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录所属用户的用户名添加到字符串s中 s += duser.GetName(); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录的父目录添加到字符串s中 s += fcontent; // 在字符串s中添加分隔符"|" s.append("|"); // 将目录的主用户权限转换为字符串并添加到字符串s中 s += to_string(masterUser); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录的其他用户权限转换为字符串并添加到字符串s中 s += to_string(otherUser); // 在字符串s中添加分隔符"|" s.append("|"); // 将目录的创建时间添加到字符串s中 s += createTime; // 在字符串s中添加分隔符"|" s.append("|"); // 将目录的修改时间添加到字符串s中 s += alterTime; // 输出字符串s ccout(s.c_str(), 6, 0); // 输出换行符 cout << endl; }
4.4全局变量
为便于确定系统运行过程中的当前用户和当前目录,以及管理所有已创建的文件、目录和用户。代码如下:
// 定义全局变量 // 定义权限枚举类型,读,写,执行 enum AccessRight { read = 1, write = 2, execute = 4 }; Directory* curdirectory = new Directory(); // 指向当前已打开目录 //File* curfile = new File(); // 指向当前已打开的文件 User* curuser = new User(); // 指向当前已登录用户 vector<Directory> dlist; // 存储目录 vector<File> flist; // 存储文件 UserList ulist; // 存储用户
4.5命令函数
命令函数的实现如下:
bool ls() // 查看当前目录 { int right = RightCheck(); // 检查当前用户权限 if (right >= AccessRight::read) // 如果权限大于等于读取权限 { curdirectory->Open(); // 打开当前目录 return true; // 返回成功 } else return false; // 返回失败 } bool useradd() // 添加用户 { string name, pw; ccout("\t用户名:", 3, 0); // 输出提示信息,要求输入用户名 cin >> name; // 读取用户输入的用户名 ccout("\t密码:", 3, 0); // 输出提示信息,要求输入密码 cin >> pw; // 读取用户输入的密码 User u(name, pw); // 创建一个User对象,传入用户名和密码 bool b = ulist.AddUser(u); // 调用ulist的AddUser方法,尝试添加用户,返回是否添加成功的布尔值 if (b) // 如果添加成功 { ccout("注册成功!\n", 14, 0); // 输出注册成功的提示信息 Directory d = *curdirectory; // 存储当前目录 *curdirectory = dlist[2]; // 将目录指针移动到home目录下 Directory udirectory(u.GetName(), u); // 创建一个Directory对象,传入用户名和User对象 dlist.push_back(udirectory); // 将新创建的Directory对象添加到dlist中 curdirectory->AddContent(udirectory.GetDName()); // 在home目录下创建用户主目录 dlist[2].AddContent(udirectory.GetDName()); *curdirectory = d; // 将指针移动回原目录 return true; // 返回添加成功的布尔值 } return false; // 如果添加失败,返回false } // 登录用户函数,接收一个字符串参数name bool su(string name) { // 定义一个字符串变量pw用于存储用户输入的密码 string pw; // 提示用户输入密码 ccout("\t请输入密码:", 3, 0); // 读取用户输入的密码 cin >> pw; // 调用ulist的Signin方法,传入用户名和密码,返回是否登录成功的布尔值 bool b = ulist.Signin(name, pw); // 如果登录成功 if (b) { // 初始化一个整数变量i为0 int i = 0; // 遍历dlist中的所有Directory对象 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) { // 如果当前遍历到的Directory对象的DName属性等于传入的用户名 if ((*it).GetDName() == name) { // 将curdirectory指向当前遍历到的Directory对象 *curdirectory = dlist[i]; // 跳出循环 break; } // i自增1 i++; } // 调用ulist的GetUser方法,传入用户名,获取对应的User对象,并赋值给curuser *curuser = ulist.GetUser(name); // 输出登录成功的提示信息 ccout("登录成功!\n", 14, 0); // 返回登录成功的布尔值 return true; } // 如果登录失败 ccout("登录失败!\n", 12, 0); // 返回登录失败的布尔值 return false; } // 删除用户的函数,接收一个字符串参数name bool userdel(string name) { // 如果当前用户是root用户 if (curuser->GetName() == "root") { // 调用ulist的DelUser方法,传入当前用户,尝试删除该用户 bool b = ulist.DelUser(name); // 如果删除成功 if (b) { // 输出删除成功的提示信息 ccout("删除成功!\n", 14, 0); // 返回删除成功的布尔值 return true; } // 如果删除失败 ccout("删除失败!\n", 12, 0); // 返回删除失败的布尔值 return false; } // 如果当前用户不是root用户 else // 输出权限不够的提示信息 ccout("权限不够!\n", 12, 0); // 返回权限不够的布尔值 return false; } // 修改用户信息的函数 bool useralt() { // 定义用户名和密码变量 string name, pw; // 提示输入用户名 ccout("\t请输入用户名:", 14, 0); // 读取输入的用户名 cin >> name; cout << endl; // 提示输入密码 ccout("\t请输入密码:", 14, 0); // 读取输入的密码 cin >> pw; cout << endl; // 如果当前用户是root或者输入的用户名与当前用户名相同 if (curuser->GetName() == "root" || curuser->GetName() == name) { // 删除原用户信息 ulist.DelUser(name); // 创建新用户对象,传入用户名和密码 User u(name, pw); // 添加新用户到用户列表中 ulist.AddUser(u); // 提示修改成功 ccout("修改成功!\n", 14, 0); // 返回true表示修改成功 return true; } // 如果当前用户不是root且输入的用户名与当前用户名不同,提示修改失败 ccout("修改失败!\n", 12, 0); // 返回false表示修改失败 return false; } bool touch(string name) // 创建文件 { File f; bool b = f.CreateFileW(name, *curuser); // 调用CreateFileW方法创建文件,返回值为布尔类型 if (!b) // 如果创建失败 { ccout("创建失败!可能有同名文件或磁盘空间不足 ", 14, 0); // 输出错误信息 return false; // 返回false表示创建失败 } flist.push_back(f); // 将创建的文件对象添加到flist向量中 curdirectory->AddFile(f.GetFName()); // 将文件名添加到当前目录的所含文件名向量中 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) // 遍历dlist向量 { if (curdirectory->GetDName() == it->GetDName()) // 如果当前目录的名称与遍历到的目录名称相同 { it->AddFile(name); // 更新该目录下的所含文件名向量,添加新创建的文件名 break; // 跳出循环 } } return true; // 返回true表示创建成功 } bool cat(string name) // 读取文件 { int right = RightCheck(); // 检查当前用户权限 if (right >= 1) // 如果权限大于等于1 { if (curdirectory->FindFile(name) != -1) // 在当前目录下查找指定文件 { for (vector<File>::iterator it = flist.begin(); it != flist.end(); it++) // 遍历文件列表 { if ((*it).GetFName() == name) // 如果找到指定文件 { (*it).ReadFileC(); // 读取文件内容 cout << endl; // 输出换行符 break; // 跳出循环 } } return true; // 返回成功标志 } else { ccout("读取失败!没找到文件\n", 12, 0); // 输出错误信息:未找到文件 } } else { ccout("读取失败!权限不够\n", 12, 0); // 输出错误信息:权限不足 return false; // 返回失败标志 } return false; // 默认返回失败标志 } bool echo(string name) // 打开并编辑文件 { int right = RightCheck(); // 检查当前用户权限 if (right >= 3) // 如果权限大于等于3 { if (cat(name)) // 尝试打开文件 { string c; getline(cin, c); // 从标准输入读取一行内容 for (vector<File>::iterator it = flist.begin(); it != flist.end(); it++) // 遍历文件列表 { if ((*it).GetFName() == name) // 如果找到指定文件 { (*it).AlterFileC(c); // 修改文件内容 break; // 跳出循环 } } return true; // 返回成功标志 } else { ccout("无此文件!\n", 12, 0); // 输出错误信息:无此文件 return false; // 返回失败标志 } } else { ccout("权限过低!\n", 12, 0); // 输出错误信息:权限不足 return false; // 返回失败标志 } } bool rm(string name) // 删除文件,只有主用户或root能删除文件 { // 遍历flist向量 for (vector<File>::iterator it = flist.begin(); it != flist.end(); it++) { // 查找文件 if ((*it).GetFName() == name) { // 权限判断 if ((*it).GetmUser().GetName() == curuser->GetName() || curuser->GetName() == "root") { // 从flist中删除文件 flist.erase(it); // 从当前目录中删除文件 curdirectory->DelFile(name); // 遍历dlist向量 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) { // 如果当前目录与目标目录相同 if (curdirectory->GetDName() == it->GetDName()) { // 更新dlist目录向量中的一个目录下的所含文件名向量 it->DelFile(name); break; } } return true; } else { // 输出权限不足的错误信息 ccout("权限过低!\n", 12, 0); return false; } } } // 输出未找到该文件的错误信息 ccout("未找到该文件!\n", 12, 0); return false; } // 创建目录函数,接收一个字符串参数name,表示要创建的目录名称 bool mkdir(string name) // 创建目录 { Directory d; // 创建一个Directory对象d bool b = d.Create(name, *curuser); // 调用Directory对象的Create方法,传入目录名称和当前用户,返回是否创建成功 if (b) // 如果创建成功 { dlist.push_back(d); // 将创建的目录添加到dlist向量中 curdirectory->AddContent(name); // 将创建的目录添加到当前目录的内容列表中 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) // 遍历dlist向量 { if (curdirectory->GetDName() == it->GetDName()) // 如果当前目录的名称与遍历到的目录的名称相同 { it->AddContent(name); // 更新遍历到的目录的内容列表中,添加新创建的目录名称 break; // 跳出循环 } } return true; // 返回创建成功 } else // 如果创建失败 { ccout("创建失败!\n", 12, 0); // 输出创建失败的信息 return false; // 返回创建失败 } } bool mvdir(string name) // 删除目录 { // 遍历dlist向量 for (vector<Directory>::iterator it1 = dlist.begin(); it1 != dlist.end(); it1++) { // 查找目录 if ((*it1).GetDName() == name) { // 权限判断 if ((*it1).GetUName() == curuser->GetName() || curuser->GetName() == "root") { // 回收目录 it1->Recycle(); // 从dlist中删除目录 dlist.erase(it1); // 从当前目录的内容列表中删除目录 curdirectory->DelContent(name); // 遍历dlist向量 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) { // 如果当前目录的名称与遍历到的目录的名称相同 if (curdirectory->GetDName() == it->GetDName()) { // 更新dlist目录向量中的一个目录下的所含目录名向量 it->DelContent(name); break; } } return true; } else { // 输出权限过低的信息 ccout("权限过低!\n", 12, 0); return false; } } } // 输出未找到该目录的信息 ccout("未找到该目录!\n", 12, 0); return false; } bool cd(string path) // 打开目录 { // 如果路径长度为1且第一个字符为'\\',则打开根目录 if (path.length() == 1 && path[0] == '\\') { *curdirectory = dlist[0]; return true; } // 将路径按照'\\'分割成字符串向量vpath vector<string> vpath = split(path, "\\"); Directory curd = *curdirectory; // 如果路径的第一个字符不为'\\',则在当前目录下查找,即通过相对路径查找 if (path[0] != '\\') { for (unsigned int i = 0; i < vpath.size(); i++) // 遍历输入的路径 { // 在当前目录下查找是否包含输入的第一个目录名 if (curdirectory->FindContent(vpath[i]) != -1) { // 遍历dlist向量 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) { // 查找目录 if ((*it).GetDName() == vpath[i]) { // 更新当前目录 *curdirectory = *it; break; } } } // 在当前目录下查找是否包含输入的第一个文件名 else if (curdirectory->FindFile(vpath[i]) != -1 && i == vpath.size() - 1) { cat(curdirectory->GetFName(curdirectory->FindFile(vpath[i]))); } // 如果未找到指定目录,则返回false else { *curdirectory = curd; ccout("未找到指定目录!\n", 12, 0); return false; } } return true; } // 如果路径的第一个字符为'\\',则在绝对路径下查找 else if (path[0] == '\\') { // 将当前目录设置为根目录 *curdirectory = dlist[0]; // 移除空向量值 vpath.erase(vpath.begin()); for (unsigned int i = 0; i < vpath.size(); i++) // 遍历输入的路径 { // 在当前目录下查找是否包含输入的第一个目录名 if (curdirectory->FindContent(vpath[i]) != -1) { // 遍历dlist向量 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) { // 查找目录 if ((*it).GetDName() == vpath[i]) { // 更新当前目录 *curdirectory = *it; break; } } } // 在当前目录下查找是否包含输入的第一个文件名 else if (curdirectory->FindFile(vpath[i]) != -1 && i == vpath.size() - 1) { cat(curdirectory->GetFName(curdirectory->FindFile(vpath[i]))); } // 如果未找到指定目录,则返回false else { ccout("未找到指定目录!\n", 12, 0); return false; } } return true; } // 如果路径不符合以上两种情况,则返回false else return false; } void ls_l() { // 获取当前目录下的文件列表 vector<string> files = curdirectory->GetFiles(); // 获取当前目录下的内容列表(包括目录和文件) vector<string> contents = curdirectory->GetContents(); // 输出表头信息 ccout("目录名 | 位置 | 大小 | 目录数量 | 文件数量 | 属主用户 | 父目录 | 主用户权限 | 其他用户权限 | 创建时间 | 修改时间 ", 6, 0); // 遍历内容列表,查找并显示目录信息 for (vector<string>::iterator itc = contents.begin(); itc != contents.end(); itc++) { for (vector<Directory>::iterator itl = dlist.begin(); itl != dlist.end(); itl++) { // 如果内容列表中的项与目录列表中的项相同,则显示目录信息并跳出循环 if (itc->compare(itl->GetDName()) == 0) { itl->View(); break; } } } // 输出文件列表的表头信息 ccout("文件名 | 位置 | 大小 | 属主用户 | 主用户权限 | 其他用户权限 | 创建时间 | 修改时间 "); // 遍历文件列表,查找并显示文件信息 for (vector<string>::iterator itf = files.begin(); itf != files.end(); itf++) { for (vector<File>::iterator itl = flist.begin(); itl != flist.end(); itl++) { // 如果文件列表中的项与文件列表中的项相同,则显示文件信息并跳出循环 if (itf->compare(itl->GetFName()) == 0) { itl->View(); break; } } } } bool alter_f(string name) // 更改文件名 { vector<string> files = curdirectory->GetFiles(); // 获取当前目录下的所有文件名 for (vector<string>::iterator itf = files.begin(); itf != files.end(); itf++) // 遍历所有文件名 { if (itf->compare(name) == 0) // 如果找到了要更改的文件名 { for (vector<File>::iterator itl = flist.begin(); itl != flist.end(); itl++) // 遍历所有文件对象 { if (itf->compare(itl->GetFName()) == 0) // 如果找到了对应的文件对象 { if (itl->GetmUser().GetName() == curuser->GetName() || curuser->GetName() == "root") // 判断权限 { string newname; // 新的文件名 ccout("新的文件名:", 3, 0); // 输出提示信息 getline(cin, newname); // 从输入流中读取新的文件名 curdirectory->AlterFileName(*itf, newname, *itl); // 调用函数更改文件名 return true; // 更改成功,返回true } else { ccout("权限过低!\n", 12, 0); // 权限不足,输出提示信息 return false; // 更改失败,返回false } } } } } ccout("未找到文件!\n", 12, 0); // 未找到文件,输出提示信息 return false; // 更改失败,返回false } bool alter_d(string name) // 更改目录名 { // 获取当前目录下的所有内容 vector<string> contents = curdirectory->GetContents(); // 遍历所有内容 for (vector<string>::iterator itc = contents.begin(); itc != contents.end(); itc++) { // 如果找到了要更改的目录名 if (itc->compare(name) == 0) { // 遍历所有目录对象 for (vector<Directory>::iterator itl = dlist.begin(); itl != dlist.end(); itl++) { // 如果找到了对应的目录对象 if (itc->compare(itl->GetDName()) == 0) { // 判断权限,如果当前用户是该目录的所有者或者当前用户是root用户 if (itl->GetUName() == curuser->GetName() || curuser->GetName() == "root") { // 输入新的目录名 string newname; ccout("新的目录名:", 3, 0); getline(cin, newname); // 调用函数更改目录名 curdirectory->AlterContentName(*itc, newname, *itl); // 更改成功,返回true return true; } else { // 权限不足,输出提示信息 ccout("权限过低!\n", 12, 0); // 更改失败,返回false return false; } } } } } // 未找到目录,输出提示信息 ccout("未找到目录!\n", 12, 0); // 更改失败,返回false return false; } bool chmod_f(string name) // 更改文件的权限 { // 获取当前目录下的所有文件名 vector<string> files = curdirectory->GetFiles(); // 遍历所有文件名 for (vector<string>::iterator itf = files.begin(); itf != files.end(); itf++) { // 如果找到了要更改权限的文件名 if (itf->compare(name) == 0) { // 遍历所有文件对象 for (vector<File>::iterator itl = flist.begin(); itl != flist.end(); itl++) { // 如果找到了对应的文件对象 if (itf->compare(itl->GetFName()) == 0) { // 判断权限是否允许修改 if (itl->GetmUser().GetName() == curuser->GetName() || curuser->GetName() == "root") { // 输入新的权限 string newright; ccout("输入权限:", 3, 0); getline(cin, newright); // 检查输入的权限格式是否正确 if (newright.length() == 2 && newright[0] - '0' <= 7 && newright[1] - '0' <= 7) { // 修改文件的权限 itl->AlterFileR(newright[0] - '0', newright[1] - '0'); } else { // 提示格式错误 ccout("格式错误!\n", 12, 0); return false; } return true; } else { // 提示权限不足 ccout("权限过低!\n", 12, 0); return false; } } } } } // 未找到文件,提示错误 ccout("未找到文件!\n", 12, 0); return false; } bool chmod_d(string name) { // 获取当前目录下的所有文件和目录 vector<string> contents = curdirectory->GetContents(); // 遍历所有内容 for (vector<string>::iterator itc = contents.begin(); itc != contents.end(); itc++) { // 如果找到了要修改权限的目录名 if (itc->compare(name) == 0) { // 遍历所有目录对象 for (vector<Directory>::iterator itl = dlist.begin(); itl != dlist.end(); itl++) { // 如果找到了要修改权限的目录对象 if (itc->compare(itl->GetDName()) == 0) { // 判断当前用户是否有权限修改该目录的权限 if (itl->GetUName() == curuser->GetName() || curuser->GetName() == "root") { // 输入新的权限值 string newright; ccout("输入权限:", 3, 0); getline(cin, newright); // 判断输入的权限格式是否正确 if (newright.length() == 2 && newright[0] - '0' <= 7 && newright[1] - '0' <= 7) { // 修改目录的权限 itl->AlterDRight(newright[0] - '0', newright[1] - '0'); } else { // 提示格式错误 ccout("格式错误!\n", 12, 0); return false; } return true; } else { // 提示权限不足 ccout("权限过低!\n", 12, 0); return false; } } } } } // 未找到目录,提示错误 ccout("未找到目录!\n", 12, 0); return false; } void ls_a() // 查看所有目录和文件的详细信息 { ccout("目录名 | 位置 | 大小 | 目录数量 | 文件数量 | 属主用户 | 父目录 | 主用户权限 | 其他用户权限 | 创建时间 | 修改时间 ", 6, 0); // 输出表头 for (vector<Directory>::iterator it = dlist.begin(); it != dlist.end(); it++) // 遍历目录列表 { it->View(); // 调用目录对象的View方法,显示详细信息 } ccout("文件名 | 位置 | 大小 | 属主用户 | 主用户权限 | 其他用户权限 | 创建时间 | 修改时间 "); // 输出文件表头 for (vector<File>::iterator it = flist.begin(); it != flist.end(); it++) // 遍历文件列表 { it->View(); // 调用文件对象的View方法,显示详细信息 } } void help() // 获取所有命令信息 { ccout("ls : 查看当前目录\n", 11, 0); ccout(" 参数有:\n\t-l + [directory_name]: 查看当前目录详细信息\n\t-a : 查看所有目录和文件的详细信息\n", 11, 0); ccout("useradd + [user_name]: 添加用户\n", 11, 0); ccout("userdel + [user_name]: 删除用户\n", 11, 0); ccout("useralt : 修改当前用户的信息\n", 11, 0); ccout("touch + [file_name]: 创建文件\n", 11, 0); ccout("cat + [file_name]: 读取文件\n", 11, 0); ccout("echo + [file_name]: 打开并编辑文件\n", 11, 0); ccout("rm + [file_name]: 删除文件\n", 11, 0); ccout("mkdir + [directory_name]: 创建目录\n", 11, 0); ccout("mvdir + [directory_name]: 删除目录\n", 11, 0); ccout("cd + [path]: 打开目录或文件\n", 11, 0); ccout("alterf + [file_name]: 更改文件名\n", 11, 0); ccout("alterd + [directory_name]: 更改目录名\n", 11, 0); ccout("chmodf + [file_name]: 更改文件权限\n", 11, 0); ccout("chmodd + [directory_name]: 更改目录权限\n", 11, 0); ccout("exit: 退出系统\n", 11, 0); }
4.6其他函数
其他函数代码实现如下:
// 获取当前时间的函数 string GetTime() { time_t timep; time(&timep); // 获取当前时间 string t1 = ctime(&timep); // 将时间转换为字符串格式 t1.pop_back(); // 删除最后一个字符 '\n' return t1; } // 隐藏控制台光标的函数 void HideConsoleCursor() { CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; SetConsoleCursorInfo(handle, &cursor_info); } // 显示控制台光标的函数 void ShowConsoleCursor() { CONSOLE_CURSOR_INFO cursor_info = { 1, 1 }; SetConsoleCursorInfo(handle, &cursor_info); } // 设置控制台文本颜色的函数 void SetColor(UINT uFore, UINT uBack) { SetConsoleTextAttribute(handle, uFore + uBack * 0x10); } // 输出带颜色和延时的字符串的函数 void ccout(const char* c, UINT uFore, UINT uBack, UINT sleeptime) { SetColor(uFore, uBack); // 设置文本颜色 if (sleeptime == 0) { cout << c; // 输出字符串 } else { HideConsoleCursor(); // 隐藏光标 for (unsigned int i = 0; i < strlen(c); i++) { cout << c[i]; // 逐个字符输出字符串 Sleep(sleeptime); // 延时 } ShowConsoleCursor(); // 显示光标 } SetColor(7, 0); // 恢复默认文本颜色 return; } // 在命令行中显示当前用户和目录信息的函数 void PutHeadInCommandLine() { ccout("<"); // 输出左尖括号 ccout(curuser->GetName().c_str()); // 输出当前用户名 ccout(" &", 6, 0); // 输出空格和右尖括号,并设置颜色为绿色 ccout(curdirectory->GetDName().c_str(), 6, 0); // 输出当前目录名,并设置颜色为绿色 ccout("> "); // 输出右尖括号和一个空格 } // 检查当前目录是否具有读写权限的函数 int RightCheck() { if (curdirectory->GetUName() == curuser->GetName()) // 如果当前目录属于当前用户 { return curdirectory->GetMRight(); // 返回当前用户的读写权限 } else return curdirectory->GetORight(); // 否则返回其他用户的读写权限 } // 将字符串按照指定模式分割成字符串数组的函数 vector<string> split(string str, string pattern) { string::size_type pos; vector<std::string> result; // 存储分割后的字符串数组 str += pattern; // 扩展字符串以方便操作 unsigned int size = str.size(); // 获取字符串长度 for (unsigned int i = 0; i < size; i++) // 遍历字符串 { pos = str.find(pattern, i); // 查找指定模式的位置 if (pos < size) // 如果找到了指定模式 { std::string s = str.substr(i, pos - i); // 截取指定模式前的子串 result.push_back(s); // 将子串添加到结果数组中 i = pos + pattern.size() - 1; // 更新索引位置 } } return result; // 返回分割后的字符串数组 }
4.7main函数
Main函数代码如下:
int main() { // 初始化系统,设置延时时间 ccout("初始化系统中...\n", 2); Sleep(100); ccout("初始化root用户...\n", 2); User uroot; uroot.SetName("root"); Sleep(1000); ccout("\t请输入root用户密码:", 2); string pw; cin >> pw; uroot.SetPasswd(pw); Sleep(1000); ccout("初始化用户列表...\n", 2); ulist.AddUser(uroot); Sleep(1000); ccout("初始化根目录...\n", 2); Directory rootdirectory; rootdirectory.Create("\\", uroot); dlist.push_back(rootdirectory); Sleep(1000); ccout("初始化home目录和root目录...\n", 2); *curdirectory = rootdirectory; Directory droot("root", uroot), dhome("home", uroot); curdirectory->AddContent(droot.GetDName()); curdirectory->AddContent(dhome.GetDName()); dlist[0].AddContent(droot.GetDName()); dlist[0].AddContent(dhome.GetDName()); dlist.push_back(droot); dlist.push_back(dhome); Sleep(1000); ccout("系统初始化完成!\n", 2); // 注册用户 ccout("注册用户:\n", 3, 0, 20); string uname, upw; ccout("\t用户名:", 3, 0); cin >> uname; ccout("\t密码:", 3, 0); cin >> upw; cout << endl; User u1(uname, upw); ulist.AddUser(u1); ulist.Signin(u1.GetName(), u1.GetPasswd()); // 切换到指定目录 *curdirectory = dlist[2]; Directory u1directory(u1.GetName(), u1); dlist.push_back(u1directory); curdirectory->AddContent(u1directory.GetDName()); dlist[2].AddContent(u1directory.GetDName()); // 显示欢迎信息和登录提示 ccout("欢迎", 3, 0, 20); ccout(curuser->GetName().c_str(), 14, 0, 20); ccout("登录本系统!\n", 3, 0, 20); *curdirectory = u1directory; // 进入命令行循环,处理用户输入的命令 ccout("\t\t\t\t| 文件管理系统 |\n", 14, 8, 20); vector<string> op; string s = ""; getline(cin, s); s.clear(); while (1) { PutHeadInCommandLine(); getline(cin, s); op = split(s, " "); int size = op.size(); // 记录命令参数 switch (size) { case(1): if (op[0] == "ls") { ls(); break; } if (op[0] == "useradd") { useradd(); getline(cin, s); break; } if (op[0] == "useralt") { useralt(); getline(cin, s); break; } if (op[0] == "help") { help(); break; } if (op[0] == "exit") { return 0; } case(2): if (op.size() != 2) { break; } if (op[0] == "userdel") { userdel(op[1]); break; } if (op[0] == "su") { su(op[1]); getline(cin, s); break; } if (op[0] == "touch") { touch(op[1]); break; } if (op[0] == "echo") { echo(op[1]); break; } if (op[0] == "cat") { cat(op[1]); break; } if (op[0] == "rm") { rm(op[1]); break; } if (op[0] == "mkdir") { mkdir(op[1]); break; } if (op[0] == "mvdir") { mvdir(op[1]); break; } if (op[0] == "mvdir") { mvdir(op[1]); break; } if (op[0] == "cd") { cd(op[1]); break; } if (op[0] == "ls") { if (op[1] == "-l") { ls_l(); break; } if (op[1] == "-a") { ls_a(); break; } } if (op[0] == "alterf") { alter_f(op[1]); break; } if (op[0] == "alterd") { alter_d(op[1]); break; } if (op[0] == "chmodf") { chmod_f(op[1]); break; } if (op[0] == "chmodd") { chmod_d(op[1]); break; } default: break; } op.clear(); s.clear(); } delete curdirectory, curuser; return 0; }
5.系统测试
测试的内容是系统是否正常运行,各种命令是否实现,内存的管理是否如期运行。
5.1系统能否正常运行
编译运行结果:
输入1:
输入用户名dong524和密码1:
测试结果:运行正常
5.2各项命令功能测试
5.2.1help
输入help:
测试结果:运行正常
5.2.2useradd
输入useradd:
输入用户名xxy,密码1:
测试结果:运行正常
5.2.3su
输入su xxy:
输入密码1:
测试结果:运行正常
5.2.4useralt
输入useralt:
输入dong524和密码1:
权限测试成功,只有用户自己和root能够修改用户信息。再次输入useralt:
输入用户名xxy和密码11:
测试结果:运行成功。
5.2.5userdel
输入userdel dong524:
权限测试成功,继续输入userdel xxy:
权限测试成功。选择登录到root用户,再输入userdel xxy:
再选择登录xxy,查看是否已经删除:
测试结果:运行成功。
5.2.6touch
输入touch one:
输入ls查看当前目录下的文件和目录,目录用&表示:
测试结果:运行正常。
5.2.7echo
输入echo one:
输入Hello World!:
再次echo one:
输入This is a file,再输入echo one:
测试结果:运行正常。
5.2.8cat
输入cat one:
测试结果:运行正常。
5.2.9rm
输入rm one,再输入ls查看当前目录:
当前目录为空,删除成功。测试结果:运行正常。
5.2.10mkdir
输入mkdir one,再输入ls查看当前目录:
测试结果:运行正常。
5.2.11mvdir
输入mvdir one,在输入ls查看当前目录:
目录删除成功。
测试结果:运行正常。
5.2.12cd
输入cd \,打开根目录:
输入ls查看根目录,并打开其中一个目录(通过相对路径访问):
输入cd \home\dong524,即通过绝对路径访问:
在该目录下创建一个one文件,并用echo写入this is a file:
再输入cd one,即通过cd命令查看文件内容:
测试结果:运行正常。
5.2.13alterf
输入alterf one,在输入one2:
输入ls查看当前目录:
文件改名成功。
测试结果:运行正常。
5.2.14alterd
先创建目录dir,再输入alterd dir,最后ls查看当前目录:
测试结果:运行正常。
5.2.15chmodf
输入chmodf one2:
权限格式为master other,分别用一个数字表示,如77、75、55、44。输入77:
输入ls -l命令查看文件权限:
测试结果:运行正常。
5.2.16chmodd
输入chmodd dir2,在输入权限77,ls -l查看详细信息:
测试结果:运行正常。
5.2.17ls
输入ls查看当前目录,有&且颜色为黄色的表示目录,白色的表示文件:
测试结果:运行正常。
5.2.18ls -l
输入ls -l查看当前目录下所有文件和目录的详细信息:
测试结果,运行正常。
5.2.19ls -a
输入ls -a查看系统所有目录和文件的详细信息:
发现标题行与信息行未回车分离,修改代码。
再次运行系统,输入ls -a:
测试结果:运行正常。
5.2.20exit
输入exit退出系统:
测试结果:运行正常。
5.3内存管理测试
在本系统中申请的1024个int型数组内存中只会存储目录名、文件名和文件内容,且都是以大小的形式将数组内存赋值为1。在申请内存时location类会从头查找maxLocation数组中第一个为0的位置,再往后查看为0的数量是否符合申请的数量,符合就将这一段全部复制为1,否则再次往后查找,直到找到符合申请的内存。系统初始化的过程中会创建4个目录,分别是根目录\、管理员目录root、用户目录home和新创建用户的主目录username,对应的大小都是目录名的大小。
查看初始化系统后的内存情况,用ls -a:
可以看见目录的大小和在虚拟内存中的位置,这些目录都是紧挨着存放的。
创建一个名为one的目录,该目录名大小为3。计算后可知道这个文件的位置将会是16。运行mkdir one,ls -a查看结果:
可以看到one目录的存储位置正如预期。
现在创建一个名为file的文件,并通过echo将this is a file写入文件中。文件名大小加上信息长度等于18,那么这个文件在内存中的位置为19,大小为18。运行touch file,echo file this is a file,ls -a查看运行结果:
可以看到文件大小和位置正如预期。再创建一个文件查看该文件的位置是否等于19+18=37:
可以看到新创建的文件dong的位置是37。
内存管理测试成功,所有代码都如期执行。至此,整个系统测试完毕,系统运行良好,各功能均已实现,文件管理系统真正落成!
6. 结语
略。。。