基于C语言实现(控制台)小型文件系统

news2026/5/14 8:01:35
♻️ 资源大小3.40MB➡️资源下载https://download.csdn.net/download/s1t16/87430288小型文件系统一、需求分析1.1 小型文件系统介绍科技的进步已将人类带入了信息大爆炸的时代随着计算机科学技术的不断发展计算机成为了许多人日常生活中必不可少的一部分不管是个人办公娱乐还是企业员工协作都无一不用到了计算机的信息管理、文件管理技术其中文件系统就是计算机上有着良好功能设计的一个系统、它通过良好的文件信息组织和简便的功能操作提供强大文件管理功能的同时还给予了使用者莫大的便捷。因此此系统的应运而生可以解决了文件的信息管理问题推动了当时计算机科学技术的深入发展。基于这种情况本文主要描述一个小型的文件管理系统的设计与实现需要注意的是本系统主要是对文件描述信息的管理并不涉及底层的磁盘存储的分配和管理。在交流和协作密切的办公环境下一个文件系统下可能有多人协同操作为了支持类似 Unix/Linux 的多用户协作和使用本文件系统也实现为一个多用户模式的文件系统。1.2 小型文件系统用户说明本系统有两类用户管理员 root 和 普通用户管理员 root可以对普通用户的添加和删除对文件系统中所有文件/目录有增删改查的权限其中包括对公共目录用于管理员向各个普通用户发送文件的所有权限。本系统只有一个管理员账号账号名 root密码root普通用户可以在自己的 Home 目录下对文件目录进行增删改查除此之外还能对公共目录的文件有查询的权限。1.3 小型文件系统功能介绍图 1 系统功能结构图系统主要功能包括登录管理员和普通用户对各自的文件目录的操作功能管理员拥有用户管理的功能而文件目录的操作功能又包含查看和更新文件目录以及切换目录的功能具体说明如下登录用户登录只有登录成功的用户才能使用本系统功能模式切换选择菜单栏模式或命令行模式信息的永久化处理所有内存数据应保存到磁盘中做永久化处理以便数据不会丢失文件管理管理员可以对根目录下的所有文件目录进行管理用户管理操作管理员还可以对普通用户进行维护管理添加、删除和修改用户信息共享目录文件的设置一个所有用户都有权限访问的文件目录文件目录操作显示当前路径信息文件目录操作显示当前路径下所有文件和子目录信息文件目录操作切换当前目录到上一级父目录文件目录操作切换当前目录到下一级选定的子目录文件目录操作在当前目录下创建一个新的空文件文件目录操作在当前目录下删除一个文件文件目录操作在当前目录下创建一个新文件夹文件目录操作在当前目录下删除一个文件夹。命令模式下支持的命令useradd、userdel、passwd、id、exit、ls、cd、 mkdir、touch、rm、pwdrebootclearchangemode 等相关的类 Linux 命令。1.4 小型文件系统具体功能需求分析1.4.1 加载数据和数据永久化功能介绍打开系统后从磁盘加载数据退出系统有数据要保存到磁盘以便下次启功时可以导入到系统用户登录功能介绍用户输入用户名和密码后登录如果登录成功进入相应的功能菜单界面或命令行如果失败则打印失败信息。输入用户名和密码输出 命令行和菜单栏界面入口或登录失败信息和登录界面1.4.2 系统模式切换功能介绍用户可以根据自己的需求自由的切换命令行模式和菜单栏模式。输入要切换的模式 ,或者 changemode 命令输出模拟命令行窗口或菜单模式等待用户操作执行命令 useradd, userdel, passwd, id, exit, ls, cd, mkdir, touch、 rm, pwd, reboot, clear, changemode命令行模式功能介绍根据用户输入的命令执行指定操作 useradd添加新用户。Userdel删除用户。passwd为用户设置密码。id查询指定用户。exit退出程序。ls查看当前目录下的文件目录。cd切换上下级目录根目录。mkdir新建文件夹。touch: 新建文件rm删除文件目录级联删除 pwd显示当前路径。reboot恢复初始化状态文件系统内容全部清空。clear命令行的清屏模式。changemode切换模式切换为菜单栏模式。输入用户命令输出命令执行后的效果信息。1.4.3 用户管理-添加用户和用户菜单栏模式功能介绍根据用户名添加用户家目录和用户密码。输入用户名和密码输出添加成功的信息或者添加失败的提示。1.4.4 用户管理-删除/修改用户菜单栏模式功能介绍根据用户名删除/修改指定用户。输入要删除/修改的用户名选项输出打印删除/修改成功或此用户不存在等失败的提示信息。1.4.5 用户管理-查询用户菜单栏模式功能介绍管理员查询当前系统所有用户信息或者单独某个用户的信息。输入可选用户明输出显示当前系统所有用户指定用户的信息。1.4.6 文件目录管理-新建文件目录菜单栏模式功能介绍在当前目录下新建一个文件或目录。输入文件目录名类型d 表示目录-表示文件大小目录固定大小以-1 代替所在首块磁盘块自动分配。输出提示新建成功或者重名冲突新建失败。1.4.7 文件目录管理-删除/修改文件目录菜单栏模式功能介绍根据文件目录名修改文件目录的相关属性。输入文件目录名选项输出打印修改/删除成功或文件目录不存在的信息。1.4.8 文件目录管理-查看文件目录信息菜单栏模式功能介绍根据输入的文件目录名编号修改此文件目录的信息输入要查看的文件目录名选项输出打印文件目录的属性信息或文件目录不存在的信息1.4.9 文件目录管理-显示当前路径信息菜单栏模式功能介绍根据当前所处位置显示当前路径信息输入无输出显示当前路径信息1.4.10 文件目录管理-显示当前文件、子目录信息菜单栏模式功能介绍根据当前所处位置显示当前路径下所有文件和子目录信息输入无2输出显示当前路径下所有文件和子目录信息1.4.11 文件目录管理-切换至子目录或上级目录菜单栏模式功能介绍根据信息在权限内切换至任意目录输入当前目录或子目录选项输出切换目录成功的界面1.4.12 文件目录管理-访问用户共享目录菜单栏模式功能介绍跳转到共享目录下输入无输出切换至共享目录后显示共享目录的界面二、系统设计2.1 系统结构设计2.1.1 本系统是一共分成五层界面层面向用户展示界面信息和读取用户的需求选择初步判断信息的合法性并把信息传递给业务处理层。业务处理层根据界面层传来的数据信息判断需要进行哪种业务处理调用并把信息传递到不同功能的函数进行实现。功能实现层对所有的业务处理层传来的信息和所需功能进行相应的分解和函数实现函数实现功能操作的对象的基础是数据结构层中的数据。数据结构层结构体顺序表孩子兄弟结点表示法的树等用于实现对数据的结构化保存。持久化数据层把数据结构层中的数据写入到文件以及从文件中读取信息动态构建相应的表和树等数据结构。2.1.2 数据结构设计数据对象设计时间对象typedef struct Date_struct { char date_str[MAX_CHAR_LEN]; //日期的整个字符串 int year; int month; int day; } Date;文件目录typedef struct FileDir { char file_name[MAX_CHAR_LEN]; //文件目录名 char type; //普通文件用- 表示目录文件用d表示 Date found_time; //建立时间 int size; //大小 int first_disk; //首块磁盘号 } FD;用户/管理员 :typedef struct User_struct { char user_name[MAX_CHAR_LEN]; //用户名 char user_passwd[MAX_CHAR_LEN]; //用户密码 char home_dir[MAX_CHAR_LEN]; //用户家目录默认为用户名管理员则为根目录/ Date found_time; //添加用户时间 } User;2.1.2 数据结构设计采用静态有序顺序表作为数据结构来存放所有的用户信息typedef User DataType; //元素的数据类型 typedef struct { DataType list[LIST_MAXSIZE]; int size; //顺序表的元素数量 } SeqList;本系统采用孩子兄弟表示法的树作为数据结构来存放所有的文件目录及其关系孩子兄弟表示法表示的树结构中有一个变量用于保存指向文件目录的指针实现了文件目录的管理和组织typedef struct Tree_srtruct { FD* fd; //文件目录 struct Tree_srtruct* fa; //当前目录的上一级目录 struct Tree_srtruct* child; struct Tree_srtruct* slib; } Tree;三、系统详细设计与实现3.1 界面层用户登录页面void LoginPage(char* account,char* password) { printf( 文件系统 \n); printf( \n); printf(| |\n); printf(| 欢迎使用文件系统 |\n); printf(| 请先登录 |\n); printf(| |\n); printf( \n); printf(账号:); scanf(%s, account); printf(密码:); scanf(%s, password); }处理流程用户输入用户名和密码并通过 name 和 passwd 的指针将结果返回给调用函数。调用函数判断是否时管理员用户名和密码如果是就登录成功继续进行登录后的业务如果不是重复等待输入。3.1.1 模块选择界面void ModeChangePage(int* choice) { printf( 文件系统 \n); printf( \n); printf(| |\n); printf(| 模式选择 |\n); printf(| 1.菜单栏模式 |\n); printf(| 2.命令行模式 |\n); printf( \n); scanf(%d, choice); }处理流程等待用户输入进行模式选择成功则根据选则进行相应功能跳转失败重复等待输入。 3.1.3 菜单栏模式界面void ManagerPage(int* choice) { printf( 文件系统 \n); printf( \n); printf(| 1.文件管理 |\n); printf(| 2.用户管理 |\n); printf(| 0.切换模式 |\n); printf(| -1.退出 |\n); printf(| -2.恢复初始化状态 |\n); printf( \n); scanf(%d, choice); }处理流程等待管理员输入进行模块选择成功则根据选则进行相应功能跳转失败重复等待输入或返回或退出。3.1.2 文件管理和用户管理界面void FDManagePage(int* choice, Tree* now_dir, char* all_fd[]) { printf( 文件系统 \n); printf( \n); printf(| 文件管理 |\n); printf(| 1.添加文件目录 2.删除文件目录 |\n); printf(| 3.修改文件目录 4.查看文件目录 |\n); printf(| 5.返回上级目录 6.进入下级目录 |\n); printf(| 7.显示当前路径 8.访问共享目录 |\n); printf(| 0.返回 -1.退出 |\n); printf( \n); TreeTrave(now_dir, all_fd); //打印当前目录下所有文件 scanf(%d, choice); }处理流程等待管理员/用户输入进行功能选择成功则根据选则进行相应功能跳转失败重复等待输入或返回或退出。void UserManagePage(int* choice) { printf( 文件系统 \n); printf( \n); printf(| 用户管理 |\n); printf(| 1.添加用户 2.删除用户 |\n); printf(| 3.修改用户 4.查询用户 |\n); printf(| 5.查看所有用户 |\n); printf(| 0.返回 -1.退出 |\n); printf( \n); scanf(%d, choice); }处理流程等待管理员输入进行功能选择成功则根据选则进行相应功能跳转失败重复等待输入或返回或退出。3.2 业务处理层用户登录业务void Login(SeqList* usr_list,char* login_name)返回类型无返回值是否含参数是含有一个保存用户信息的链表指针和用户名的字符串指针。步骤调用 LoginPage 函数展示登录界面并从登录界面中得到用户输入的用户名和密码根据用户名和密码以及存有用户信息的 usr_list 判断用户名和密码是否合法 C.合法则登录成功并跳转到模式选择页面否则提示用户密码错误重新展示登录界面等待用户操作3.2.1 模式切换业务int ModeChange()返回类型int是否含参数否步骤展示模式切换界面获取选项根据选项进行模式选择跳转3.2.2 菜单模式业务int MenuMode(SeqListusr_list, charsuccess_name,Tree* root) 返回类型int用于切换模式是否含参数是含有一个保存用户信息的链表指针和用户名的字符串指针以及存放所有文件的结构体指针。步骤判断登录者是管理员还是用户是管理员则展示文件管理或者用户管理模块并响应对应模块的的请求执行业务逻辑处理否则仅展示用户对应的文件管理模块进行业务处理返回值用于判断是否切换模式本系统测试以管理员为例3.2.3 命令行模式业务int CmdMode(SeqListusr_list, charsuccess_name, Tree* root) 返回类型int用于切换模式。是否含参数是含有一个保存用户信息的链表指针和用户名的字符串指针以及存放所有文件的结构体指针。步骤输入命令行标识符等待用户输入命令根据输入的命令去调用命令执行函数命令执行函数把执行结果展示出来3.2.4 用户管理的业务处理菜单模式void AddUserBP(SeqListusr_list,Treehome_dir) 返回类型无。是否含参数是含有一个执行当前目录的结构体指针一个用户列表指针。步骤调用 AddUserPage 获取用户的输入的新用户的名字和密码调用 AddUser 把得到的用户添加到用户列表 usr_list 中添加失败则终止业务添加成功则在/home 目录下创建一个与用户名相同的子目录void DelUserBp(SeqListusr_list,Treehome_dir) 返回类型无。是否含参数是含有一个执行当前目录的结构体指针一个用户列表指针。步骤调用 AddUserPage 获取用户要删除的用户名调用 DelUser 把该用户添加从列表 usr_list 中删除删除失败则中止业务删除成功则把/home 目录下与用户名相同的子目录删除void ModifyUserBP(SeqList* usr_list) 返回类型无。是否含参数是含有一个存放用户信息的列表指针。步骤调用 ModifyUserPage 获取用户要修改的用户名以及新密码判断密码是否为-1-1 表示取消修改否则调用 ModifyUser 修改 usr_list 中的用户密码void IDUserBP(SeqList* usr_list) 返回类型无。是否含参数是含有一个存放用户信息的列表指针。步骤调用 IDUserPage 获取用户要查看的用户名否则调用 IDUser 查看 usr_list 中的用户信息void AllUserBP(SeqList* usr_list) 返回类型无。是否含参数是含有一个存放用户信息的列表指针。步骤调用 AllIDUser 要展示 usr_list 中所有的用户信息3.2.5 文件目录的业务处理菜单模式int AddFDBP(Tree* now_dir)返回类型int表示处理的成功与否。是否含参数是含有一个指向当前目录的结构体指针。步骤判断 now_dir 是否为目录若非目录则终止业务处理调用 AddFdPage 获取用户的输入的新文件目录参数判断当前目录下有无同名的冲突文件或目录有则终止业务新建一个新的文件目录把该文件目录放在当前目录下int DelFDBP(Tree* now_dir,char* all_fd[])返回类型int表示处理的成功与否。是否含参数是含有一个执行当前目录的结构体指针以及一个指针数组用于选定删除的文件目录。步骤调用 DelFdPage 获取用户要删除的文件目录选项判断该文件目录名是否存在存在则在当前目录下删除该文件目录int ModifyFDBP(Treenow_dir, charall_fd[]) 返回类型int表示处理的成功与否。是否含参数是含有一个指向当前目录的结构体指针以及一个指针数组用于选定修改的文件目录。调用 ModifyFdPage 获取用户要修改的文件目录选项调用 AddFdPage 获取用户的输入的新文件目录参数判断该文件目录名是否存在不存在则终止业务判断当前目录下有无同名的冲突文件或目录有则终止业务新建一个新的文件目录把该文件目录放在当前目录下int ShowFDBP(char* all_fd[])返回类型int表示处理的成功与否。是否含参数是含有一个指针数组用于选定展示的文件目录。步骤调用 ShowFDPage 获取用户要查看的文件目录选项判断该文件目录名是否存在存在则展示该文件目录不存在则终止业务。void CdChildBP(Tree** now_dir, char* all_fd[]) 返回类型无是否含参数是含有一个二级指针和一个指针数组用于选定展示的文件目录。步骤调用 CdChild 获取用户要进入的下级目录选项从 all_fd 中取出该目录对应的指针把取出的指针赋值給二级指针 now_dir 指向的内容表示目录切换成功void PwdBP(Tree* now_dir) 返回类型无。是否含参数是含有一个指向当前目录的结构体指针。步骤把 now_dir 的目录名存放到一个二维字符数组中用 pnow_dir-fa 得到当前目录的上一级目录把上级目录的目录名存到二维字符数组中重复 BC 直到目录为根目录/把二维字符数组中的目录名倒序输入并在它们之间加上字符/3.2.6 根据不同命令进行业务处理命令行模式int parseline(char *buf, char **argv) 返回类型int;代表 argv 中的个数是否含参数是含有一个字符指针 buf命令 参数和一个二级指针buf 分割后的内容。步骤用空格替换行末换行符删除行首空格利用空格作为分割符把 buf 中的字符分割到 argv 中返回分割后得到的字符串个数int executeCmd(char* cmdline, SeqList* usr_list, char* success_name, Tree* root, Tree** now_dir)返回类型int用于切换模式。是否含参数是含有一个保存用户信息的链表指针和用户名的字符串指针以及存放所有文件的结构体指针和指向当前目录的指针和存放命令的字符数组。步骤调用 parseline 把命令进行分割根据分割后的内容调用不同的功能实现函数进行实现实现成功后展示给用户失败则给出提示3.3 功能实现层3.3.1 文件目录相关功能实现Date MakeCurDate() 返回类型Date;是否含参数无步骤调用库函数 ctime,time,localtime 等获取当前时间新建一个 Date 结构体把获取到的时间分割出年月日和时间戳字符串分别保存在 Date 里将得到的 Date 返回FD* MakeFD(char* f_n, char t, int s) 返回类型FD*;是否含参数是含有一个指针指向文件名类型字符文件大小步骤根据文件目录名文件目录类型文件目录大小生成一个文件目录结构体调用 MakeCurDate 获取当前时间的 Date 结构体把 Date 结构体保存进 FD 中返回一个指向该 FD 结构体的指针void FreeFD(FD* fd)。返回类型无;是否含参数是含有一个指针指向文件目录步骤A根据指向该文件目录 FD 的结构体指针调用 free()释放该指针指向的内存。3.3.2 树结构对文件目录的组织和管理功能实现void TreeRootInit(Tree* root) 返回类型无;是否含参数是含有一个代表根目录的树结点指针步骤新建三个文件目录分别为根目录共享目录和用户家目录把根目录的指针初始化把根目录放进根目录指针中在根目录下加入共享目录和家目录void TreeNodeInit(Tree* t) 返回类型无;是否含参数是含有一个树结点指针步骤把指针指向的内容各个变量都置为 NULLvoid TreeAdd(Tree* t,FD* fd) 返回类型无;是否含参数是含有一个代表文件目录的树结点指针和一个文件目录指针步骤判断 t 是否为目录fd 是否为非空不满足条件则结束寻找 t 的孩子结点寻找该孩子结点的兄弟结点若无则跳转 F判断该兄弟结点是否还有兄弟结点若仍有兄弟结点重复 CD若无兄弟结点则新建一个结点并把 fd 放进去作为该结点的兄弟结点Tree* TreeGet(Tree* t, char* f_n) 返回类型树结点指针;是否含参数是含有一个代表文件目录的树结点指针和一个代表文件名的指针步骤判断 t 是否为目录f_d 是否为非空不满足条件则结束寻找 t 的孩子结点判断该结点代表的文件目录名是否与 f_d 相同相同则跳转到步骤 H寻找该孩子结点的兄弟结点判断该结点代表的文件目录名是否与 f_d 相同相同则跳转到步骤 H判断该兄弟结点是否还有兄弟结点若仍有兄弟结点跳转到步骤 D无则结束返回指向该树结点的指针。void TreeDel(Tree* t, char* f_n) 返回类型无;是否含参数是含有一个代表文件目录的树结点指针和一个代表文件名的指针步骤判断 t 是否为目录f_d 是否为非空不满足条件则结束寻找 t 的孩子结点判断该结点代表的文件目录名是否与 f_d 相同相同则跳转到步骤 I寻找该孩子结点的兄弟结点判断该结点代表的文件目录名是否与 f_d 相同相同则跳转到步骤 I判断该兄弟结点是否还有兄弟结点若仍有兄弟结点跳转到步骤 D无则结束若改结点是 t 的孩子结点则把 t 的孩子结点更新为该结点的第一个兄弟结点释放该节点。若不是则把该结点所在的兄弟链里删除并释放该结点。void TreeTrave(Tree* t,Tree* all_FD[]) 返回类型无;是否含参数是含有一个代表文件目录的树结点指针和一个树结点指针数组步骤判断 t 是否为目录不满足条件则结束寻找 t 的孩子结点把该结点代表的文件目录名输出并编号存在 all_fd 中寻找该结点的兄弟结点把该结点代表的文件目录名输出并编号存在 all_fd 中不存在则跳转到 F判断该兄弟结点是否还有兄弟结点若仍有兄弟结点重复 CD若无兄弟结点则新建一个结点并把 fd 放进去作为该结点的兄弟结点void FreeTree(Tree* t) 返回类型无;是否含参数是含有一个代表文件目录的树结点指针步骤判断 t 是否为 NULL是则结束该函数判断 t 是否有孩子结点有则递归释放该孩子结点判断 t 是否有兄弟结点有则递归释放该兄弟结点释放 t 结点本身3.3.3 用户管理功能实现User MakeUser(char* u_name, char* u_passwd) 返回类型一个用户结构体;是否含参数是含有指向用户名和密码的字符数组指针步骤新建一个 User 结构体把 u_name 和 u_passwd 拷贝进 User新建一个代表当前时间的 Date 结构体并拷贝进 User返回一个 User 结构体void InitUserList(SeqList* user_list) 返回类型无;是否含参数是含有一个列表结构体指针步骤调用 ListInit 函数对 user_list 进行初始化int IsUserLegal(SeqList* user_list, char* u_name, char* passwd)返回类型int;是否含参数是含有一个列表结构体指针指向用户名和密码的字符数组指针步骤user_list 取出名为 u_name 的用户结构体指针不存在则返回 0存在则比较该用户的密码是否与 passwd 相同相同则返回 1否则返回 0int AddUser(SeqList* user_list, char* u_name,char* u_passwd)返回类型int;是否含参数是含有一个列表结构体指针指向用户名和密码的字符数组指针步骤判断 user_list 中是否有为 u_name 的用户有则返回 0无则新建一个用户名和密码为 u_name,u_passwd 的 User把该 User 插入到 user_list返回 1。int DelUser(SeqList* user_list, char* u_name)返回类型int;是否含参数是含有一个列表结构体指针指向用户名的字符数组指针步骤判断 user_list 中是否有为 u_name 的用户无则返回 0有则将该 User 从 user_list 中删除返回 1。int ModifyUser(SeqList* user_list, char* u_name, char* u_passwd, char* home_dir) 返回类型int;是否含参数是含有一个列表结构体指针指向用户名和密码的字符数组指针步骤判断 user_list 中是否有为 u_name 的用户无则返回 0有则将该 User 的密码和家目录改为 u_passwd 和 home_dir若为-1 则不更改返回 1。int IDUser(SeqList* user_list, char* u_name)返回类型int;是否含参数是含有一个列表结构体指针指向用户名的字符数组指针步骤判断 user_list 中是否有为 u_name 的用户有则打印该用户的信息有则打印该用户的信息并返回 1无则返回 0。void AllIDUser(SeqList* user_list) 返回类型无 是否含参数是含有一个列表结构体指针步骤遍历 user_list 中的用户遍历过程中把用户的信息打印出来3.4 持久化数据层3.4.1 读取配置信息int ReadConfigMsg(SeqList* usr_list) 返回类型int;是否含参数是含有一个存放用户信息的链表结构体指针。步骤判断配置文件 config.init 是否为空空则结束非空则读取文件内容看第一行是否为 1是则表示系统属于不属于初次打开因此调用则调用 ReadUserFromFile 读取保存用户信息的文件否则表示初始打开系统读取文件中的前两行表示管理员账号和密码把他们读入 user_list 中并且写入保存用户信息的文件中往 config.init 中写入一个 1 表示已经打开过了。3.4.2 用户数据和文件目录文件读写void WriteUserToFile(SeqList* usr_list) 返回类型无;是否含参数是含有一个存放用户信息的链表结构体指针。步骤打开用户信息文件 user.config 是否为空遍历 usr_list把 usr_list 中的用户信息按二进制写入文件中关闭文件void ReadUserFromFile(SeqList* usr_list) 返回类型无;是否含参数是含有一个存放用户信息的链表结构体指针。步骤打开用户信息文件 user.config若不存在文件则结束把读到的用户信息保存至 usr_list 中关闭文件void WriteTreeToFile(Tree* root) 返回类型 无是否含参数是含有一个指向根目录的树结点指针;。步骤打开文件目录信息文件 fd.config树结点文件 treenode.config若不存在文件则结束新建一个队列将 root 结点入队列当队列非空则出队列并把队列中的内容分别写入文件 fd.config 和 treenode.config若出队指针孩子结点非空入队列若出队指针兄弟节点非空再把兄弟结点入队列重复 DEF 至队列为空关闭所有文件。Tree* ReadTreeFromFile() 返回类型 无是否含参数是含有一个指向根目录的树结点指针;。步骤打开文件目录信息文件 fd.config树结点文件 treenode.config读入信息到 root若 root 为空则结束新建一个队列将 root 结点入队列当队列非空则出队列否则关闭所有文件函数结束若出队指针孩子结点非空从文件中读入一个结点作为该出队结点的孩子结点把读取的结点指针入队列若出队指针兄弟结点非空从文件中读入一个结点作为该出队结点的兄弟结点把读取的结点指针入队列重复 DEF。3.4.3 初始化程序信息、保存信息终止程序、恢复原始设置void InitProcess(SeqListusr_list,Treeroot,char** login_name) 返回类型 无是否含参数是含有三个二级指针分别代表用户列表根节点登录名。步骤新建一个保存用户信息的列表并初始化调用 ReadConfigMsg()读取配置信息和用户信息调用 ReadTreeFromFile()读取文件目录信息若读取后 root 指向的内容仍为空则创建一个内存给 root并初始化根节点为登录名创建所需空间void KillProcess(SeqListusr_list, Treeroot, char* login_name) 返回类型 无是否含参数是含有三个指针分别代表用户列表根节点登录名。步骤调用 WriteUserToFile()把用户信息写入文件调用 WriteTreeToFile()把根节点代表的整个文件系统写入文件调用 ReadTreeFromFile()读取文件目录信息释放 usr_listrootlogin_name 的s内存空间void Reboot(SeqListusr_list, Treeroot, char* login_name) 返回类型 无是否含参数是含有三个指针分别代表用户列表根节点登录名。步骤打开保存初始化配置用户信息和文件目录树结点的文件把初始管理员账号密码写入配置文件把存储用户信息和文件信息的文件清空关闭所有文件。3.5 函数调用关系四、系统运行测试结果及分析4.1 登录测试测试模块如表 4-1 所示。表 4-1测试模块名称输入输出测试结果管理员登录root root模式选择菜单通过管理员登录root 123提示登录失败通过用户登录caijunqian 123456模式选择菜单通过4.2 命令行模块测试注意另外还有 clear 清空屏幕命令reboot 恢复初始化设置命令。4.3 菜单栏模块测试用户管理文件管理注系统恢复初始化退出模式切换数据的保存和文件读写在验收时测试。五、总结遇到的问题刚拿到题目不知道如何下手才能更好更快的进行开发担心向以前写的课程系统一样调试起来特别麻烦头文件的包含不是很理解读入 char 字符时遇到奇怪问题孩子兄弟表示法的树结构不知道如何写入文件后读出来还能构建成树多个指针类型的保存以及二级指针的灵活使用问题解决利用软件分层的思想把系统开发分解成多个层面想清楚每个层需要解决的问题和提供的接口。减少各个层之前的耦合性。每个模块的函数写完后可以新建一个测试函数在测试函数里调用这些函数进行测试。然后 main 函数调用该测试函数对该模块进行整体测试还可以利用宏#ifdef AAA #endif 来输出调试过程的信息。在 bug 解决完后可以取消 def AAA。将一些共享的很多个文件都会用到的声明放到一个头文件中该文件可以没有对应的.c 文件只给其它文件用于包含头文件。scanf 读入 char 类型的字符时必须把键盘的缓冲区清空因为它可读入回车空格等字符通过利用队列进行层序遍历的方式把孩子兄弟表示法的二叉树写入文件中在读取的时候逐个读取根据读取到的结构体的孩子结点或兄弟结点的指针是否为空判断下一个读入的结构体是否赋值为前一个的孩子结点或兄弟结点(已在附录中给出核心代码)通过二级指针可以实现指针的修改char* 数组可以保存不同类型的指针使用时进行强制转换即可。六、附录核心代码把孩子兄弟表示法的树写入文件和读出来动态构建树的相关代码void WriteTreeToFile(Tree* root) { Tree* p ; FILE* fp1 fopen(./fd.config, w); FILE* fp2 fopen(./treenode.config, w); FILE* fp3 fopen(./numOfDisk.config, w); SeqQueue myQueue; fprintf(fp3, %d, G_DISK_NUM); QueueInit(myQueue); QueueAppend(myQueue, root); //将根结点入队 while (QueueNotEmpty(myQueue))//当队列非空 { QueuePop(myQueue, p); //出队并写入文件 //写入文件 fwrite((void*)p-fd, sizeof(FD), 1, fp1); fwrite((void*)p, sizeof(Tree), 1, fp2); //将左孩子入队再将右孩子入队 if (p-child ! NULL)QueueAppend(myQueue, p-child); if (p-slib ! NULL)QueueAppend(myQueue, p-slib); } fclose(fp1); fclose(fp2); fclose(fp3); } /*依次把配置文件treenode.config、fd.config读入构建树*/ Tree* ReadTreeFromFile() { FD* fdNULL; Tree* tpNULL; Tree* p NULL; Tree* root; SeqQueue myQueue; FILE* fp1 fopen(./fd.config, r); FILE* fp2 fopen(./treenode.config, r); FILE* fp3 fopen(./numOfDisk.config, r); QueueInit(myQueue); //先把根节点读入 root (Tree* )malloc(sizeof(Tree)); fd (FD*)malloc(sizeof(FD)); fread(fd, sizeof(FD), 1, fp1); p fread(root, sizeof(Tree), 1, fp2); if (p NULL) { return NULL; //配置文件为空不需要构建树 } if(fp3!NULL)fscanf(fp3, %d, G_DISK_NUM); root-fd fd; //根据根节点的child,slib是否为空构建整颗树 QueueAppend(myQueue, root); while (QueueNotEmpty(myQueue))//当队列非空 { QueuePop(myQueue, p); //出队 if (p-child ! NULL) { //读入它孩子入队列 tp (Tree*)malloc(sizeof(Tree)); fd (FD*)malloc(sizeof(FD)); fread(fd, sizeof(FD), 1, fp1); fread(tp, sizeof(Tree), 1, fp2); tp-fd fd; p-child tp; tp-fa p; //指向父亲节点 QueueAppend(myQueue, tp); } if (p-slib ! NULL) { //读入它兄弟入队列 tp (Tree*)malloc(sizeof(Tree)); fd (FD*)malloc(sizeof(FD)); fread(fd, sizeof(FD), 1, fp1); fread(tp, sizeof(Tree), 1, fp2); tp-fd fd; p-slib tp; tp-fa p-fa; //指向父亲节点 QueueAppend(myQueue, tp); } } fclose(fp1); fclose(fp2); fclose(fp3); return root; }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2611565.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…