type
status
date
slug
summary
tags
category
icon
password
文件管理器设计方案一、项目简介二、系统架构2.1 类2.2 文件系统的实现三、功能实现3.1 格式化3.2 创建子目录3.3 删除子目录3.4 显示目录3.5 更改当前目录3.6 创建文件3.7 打开文件3.8 关闭文件3.9 写文件3.10 读文件3.11 删除文件3.12 显示属性3.13 修改图形大小3.14 操作写入磁盘3.15 显示磁盘使用率四、用户界面设计4.1 整体界面4.2 功能点界面展示五、总结5.1 心得体会5.2 改进方向Reference
文件管理器设计方案
一、项目简介
- 项目内容:在内存中开辟一个空间作为文件存储器,实现一个简单的文件系统。退出这个文件系统时,需要将文件系统的内容保存到磁盘上,以便下次可以将其恢复到内存中来。文件系统需要提供的操作包括:格式化、创建子目录、删除子目录、显示目录、更改当前目录、创建文件、打开文件、关闭文件、写文件、读文件、删除文件等。
- 开发环境
- 系统:Windows 11 家庭中文版
- IDE:PyCharm Community Edition 2022.2
- Python 解释器:Python版本为3.8.16,且已通过pip安装了PyQt5
二、系统架构
2.1 类
类名 | 作用 |
Block | 物理块类,代表磁盘中的一个物理块。
每个物理块有一个编号和一个数据字段,可以进行读写操作。 |
FAT | 文件分配表类,用于管理磁盘中的物理块。
FAT表中的每一项都代表一个物理块的状态,可以进行物理块的分配、释放、读取和更新等操作。 |
FCB | 文件控制块类,用于存储文件的元数据,包括文件名、创建时间、最后修改时间等。
FCB有一个指向FAT的引用,用于管理文件的物理块。 |
Catalog | 目录类,代表文件系统中的一个目录或者文件。如果是目录,有一个子结点列表;如果是文件,有一个FCB来存储文件的元数据。 |
ListWidget | 继承自QListWidget,支持拖放操作,并且可以编辑其项目。
它还包含一些用于管理其当前编辑状态的方法。 |
EditingInterface | 继承自Qwidget,表示文本编辑时的界面。
包含一个 QTextEdit,用于编辑文件内容。它还包含一些用于管理编辑状态的方法。 |
AttributeInterface | 继承自Qwidget,表示文件/文件夹属性的界面。
显示文件或文件夹的属性,如名称、创建时间、修改时间等。 |
FileSystem | 继承自QMainWindow,一个全面的文件系统 GUI。
提供了一系列的方法和功能,使用户能够方便地浏览和管理文件系统。 |
Base.py中的四个类的类图如下:
2.2 文件系统的实现
在这个项目中,文件存储空间管理、空闲空间管理和文件目录的实现方式如下:
- 文件存储空间管理:本项目使用了链接结构来管理文件存储空间。FAT类中有一个列表,每个元素代表一个物理块的状态。如果物理块被占用,列表中的对应元素就是下一个物理块的索引;如果物理块是文件的最后一个物理块,列表中的对应元素就是-1;如果物理块是空闲的,列表中的对应元素就是-2。通过这种方式,我们可以通过FAT表来找到文件的所有物理块。
- 空闲空间管理:本项目也是在FAT类中实现空闲空间管理的。FAT类有一个方法findBlank,它会遍历FAT表,找到第一个状态为-2的物理块,然后返回它的索引。这就相当于找到了一个空闲的物理块。当需要写入新的数据时,就可以使用这个方法来找到空闲的物理块。
- 文件目录:这个项目使用了多级目录结构,具体实现在Catalog类中。Catalog类代表了一个目录或者一个文件。如果Catalog是一个目录,它就有一个子结点列表;如果Catalog是一个文件,它就有一个FCB(文件控制块)来存储文件的元数据,包括文件名、创建时间和最后修改时间。FCB类有一个指向FAT的引用,用于管理文件的物理块。
- 退出文件系统时的保存:在退出文件系统时,我们需要将文件系统的内容保存到磁盘上。这个功能在closeEvent方法中实现。这个方法首先会询问用户是否需要将本次操作写入磁盘。如果用户选择写入,那么就会将FAT表、磁盘和目录结构序列化后写入到本地的文件中。这样,下次启动文件系统时,就可以从这些文件中读取数据,将文件系统的状态恢复到内存中。
三、功能实现
3.1 格式化
使用
FileSystem.format
来实现首先,它会结束任何正在进行的编辑操作,并弹出一个提示框询问用户是否确定要格式化磁盘。如果用户选择取消,那么格式化操作就会被终止。如果用户选择确定,那么程序会创建一个新的文件分配表、一个新的磁盘和一个新的目录,然后将它们分别写入到对应的文件中,完成文件系统的格式化。最后,程序会重新加载页面,显示新的文件系统状态。
3.2 创建子目录
使用
FileSystem.create_folder
来实现首先,它在用户界面上创建一个新的文件夹项,并允许用户编辑文件夹的名称。然后,它在文件系统的目录表中添加一个新的节点来代表这个新创建的文件夹,这个新节点的父节点是当前节点。最后,它更新目录树的显示,以反映新创建的文件夹。这个过程实现了在图形用户界面和文件系统中同时创建新文件夹的功能。
3.3 删除子目录
使用
FileSystem.delete
来实现首先,它检查用户是否选择了一个文件或文件夹,如果没有选择,操作会被终止。然后,它弹出一个提示框询问用户是否确定要删除选中的文件或文件夹。如果用户选择取消,那么删除操作就会被终止。如果用户选择确定,那么程序会开始删除选中的文件或文件夹。具体来说,它会从列表视图中移除选中的项,然后删除这个项。同时,它会递归地删除选中的节点以及它的所有子节点。最后,它会更新目录表和目录树的显示,以反映删除操作的结果。这个过程实现了在图形用户界面和文件系统中同时删除文件或文件夹的功能。
3.4 显示目录
在初始化用户界面的过程中,程序设置了一个导航栏,这是一个地址树部件,它展示了文件系统的目录结构。用户可以通过点击树中的项来导航到不同的目录。同时,程序也设置了一个列表视图,它用于显示当前目录下的所有文件和子目录。用户可以通过双击列表视图中的项来打开文件或进入子目录。此外,程序还有一个更新地址栏的方法,它会更新地址栏的内容以反映当前的路径,这为用户提供了一个清晰的视觉反馈,帮助他们理解当前所在的目录。
3.5 更改当前目录
本项目有三种方式来实现更改当前目录:
3.5.1 点击展示栏图标跳转
在
FileSystem.open_file
中实现当用户点击一个项时,程序首先会关闭可能正在进行的文件编辑。然后,它会尝试获取用户点击的项,如果无法获取,它会检查用户是否选中了一个或多个项,如果用户选中了,那么它会获取最后一个选中的项。接着,它会检查是否可以进行前进操作,如果可以,那么它会获取上一次的位置对应的项,并重置相关的状态。最后,它会在当前节点的子节点中查找与用户点击的项名称相同的节点,如果找到,那么这个节点就会成为新的当前节点,从而实现了更改当前目录的功能。
3.5.2 点击导航栏上的跳转
使用
FileSystem.click_item
来实现首先,它获取了用户点击的项以及这个项的所有父项,这些项组成了用户要跳转的路径。然后,它将当前节点回退到根节点,接着遍历用户要跳转的路径,对于路径中的每一个项,它都会找到这个项对应的节点,并将当前节点设置为这个节点。同时,它还会更新当前的地址和目录树。最后,它会更新地址栏的显示,设置回退和前进按钮的可用状态,以及更新上一次的位置。这个过程实现了在图形用户界面和文件系统中同时进行跳转的功能。
3.5.3 跳转上级/下级目录
分别在
FileSystem.backward
与FileSystem.forward
中实现返回上一级:backward方法实现了返回上一级目录的功能。首先,它会关闭可能正在进行的文件编辑。然后,如果当前节点是根节点,那么它无法返回,方法会直接返回False。如果当前节点不是根节点,那么它会记录当前节点在其父节点的子节点列表中的位置,然后将当前节点设置为其父节点。接着,它会更新当前的地址和目录树。最后,如果当前节点变成了根节点,那么它会禁用后退按钮。如果成功返回上一级目录,方法会返回True。
跳转下一级:forward方法实现了跳转到下一级目录的功能。它首先将nextStep设置为True,然后调用open_file方法。在open_file方法中,如果nextStep为True,并且lastLoc不等于-1,那么它会获取lastLoc对应的项,并重置lastLoc和nextStep。然后,它会在当前节点的子节点中查找与用户点击的项名称相同的节点,如果找到,那么这个节点就会成为新的当前节点,从而实现了跳转到下一级目录的功能。
3.6 创建文件
使用
FileSystem.create_file
来实现首先,它创建了一个新的列表项,表示新的文件,并将其添加到列表视图中。然后,它创建了一个新的节点,表示新的文件,并将其添加到当前节点的子节点列表和目录表中。最后,它更新了地址树,以反映新创建的文件。
3.7 打开文件
使用
FileSystem.open_file
来实现首先,尝试获取用户点击的项目,如果项目是文件,会读取文件数据并打开一个编辑窗口显示文件内容。如果项目是目录(文件夹),会更新当前节点为新节点,并加载新节点的文件。然后,更新当前路径,并在树状视图中找到新节点对应的项目,并设置为当前项目。最后,更新了地址栏和地址树,以反映打开的文件或进入的文件夹。
3.8 关闭文件
使用
EditingInterface.closeEvent
来实现当用户尝试关闭文件时,系统首先检查文件是否被修改过。如果文件内容没有变化,系统会直接关闭文件。如果文件被修改过,系统会弹出一个对话框询问用户是否想要保存更改。用户有三个选项:保存更改,不保存更改,或取消关闭操作。如果用户选择保存更改,系统会保存文件并关闭它。如果用户选择不保存更改,系统会直接关闭文件而不保存任何更改。如果用户选择取消关闭操作,系统会忽略关闭请求并保持文件打开状态。
3.9 写文件
在
FileSystem.open_file
中实现首先,系统会打开一个编辑窗口,用户可以在这个窗口中输入文件的内容。当用户完成编辑并关闭窗口时,系统会获取用户输入的内容,并将这些内容写入到文件中。
具体来说,当用户打开一个文件时,系统会读取文件的数据,并在一个编辑窗口中显示这些数据。用户可以在编辑窗口中修改文件的内容。当用户关闭编辑窗口时,系统会获取窗口中的内容,并将这些内容写入到文件中。这个过程是通过getData函数完成的,这个函数会获取编辑窗口中的内容,并将这些内容更新到文件中。如果用户打开的是一个目录,系统会关闭可能正在进行的文件编辑,更新当前节点,并加载新节点的文件。然后,系统会更新当前路径,并在树状视图中找到新节点对应的项目,并设置为当前项目。最后,系统会更新地址栏。在这个过程中,系统会不断更新树状视图,以反映文件系统的当前状态。
3.10 读文件
当用户选择打开一个文件时,系统会首先在当前节点的子节点中查找与用户选择的项目名称相同的节点。如果找到的节点是文件,系统会读取文件的数据,并在一个编辑窗口中显示这些数据。
具体来说,读取文件的过程是通过
newNode.data.read(self.fat, self.disk)
这行代码完成的。在这行代码中,newNode是用户选择的文件对应的节点,data是文件的数据,read是读取数据的方法,self.fat和self.disk是文件系统的参数。读取文件的数据后,系统会创建一个编辑窗口,这个窗口的名称是文件的名称,窗口中的内容是文件的数据。用户可以在这个窗口中查看文件的内容,也可以修改文件的内容。当用户关闭编辑窗口时,系统会获取窗口中的内容,并将这些内容写入到文件中,这就完成了对文件的读取和写入操作。3.11 删除文件
使用
FileSystem.delete
来实现首先,它检查是否有选中的项目。如果没有,函数就会直接返回。然后,它获取选中的项目和其在列表中的索引。接着,弹出一个提示框,询问用户是否确定要删除选中的文件。如果用户选择取消,函数就会直接返回。如果用户选择确定,就会从列表中删除选中的项目,并定义一个内部函数deleteFileRecursive,用于递归删除文件。最后,调用deleteFileRecursive函数,删除在文件分配表中的内容,并从当前节点的子节点中删除选中的节点。
3.12 显示属性
在
AttributeInterface
类中,可以显示文件或文件夹的属性。在初始化这个类时,其会接收一些参数,如名称、是否为文件、创建时间、更新时间和子节点数量。然后,创建一个选项卡小部件,并添加一个名为"详细信息"的选项卡。在这个选项卡中,会显示文件或文件夹的名称、创建时间、更新时间(如果是文件)或内部项目数量(如果是文件夹)。文件或文件夹的名称前面会有一个图标,文件的图标是一个文件图像,文件夹的图标是一个文件夹图像。3.13 修改图形大小
在
FileSystem.show_menu
中实现通过在右键菜单中添加一个名为"查看"的子菜单实现的,该子菜单包含了"大图标"、"中等图标"和"小图标"三个选项。每个选项都关联到一个函数,这个函数会根据用户的选择来调整图标的大小。具体来说,当用户选择了一个选项后,会触发一个名为set_icon_and_grid_size的函数,将列表视图的图标大小和网格大小设置为给定的值(具体有大中小三种视图)。例如,如果用户选择了"大图标",那么图标的大小就会被设置为172x172,网格的大小会被设置为200x200。
3.14 操作写入磁盘
在
FileSystem.closeEvent
中实现当用户尝试关闭程序时,系统会弹出一个消息框询问用户是否需要将本次的操作写入磁盘。如果用户选择"写入",那么程序会将内存中的文件系统状态存储到本地磁盘。具体来说,它会将FAT表、磁盘表和目录表分别序列化后写入到名为fat、disk和catalog的文件中。如果用户选择"不写入",那么程序会直接关闭,本次的操作不会被保存到磁盘。如果用户选择"取消",那么关闭程序的操作会被取消,程序会继续运行。
这个过程是通过Python的pickle模块实现的,该模块可以将Python对象序列化为字节流,然后再将这个字节流写入到文件中。这样,下次启动程序时,就可以从这些文件中读取数据,反序列化为Python对象,从而恢复文件系统的状态。
3.15 显示磁盘使用率
使用
FAT.get_usage_percentage
方法来实现通过遍历FAT表,计算出被占用的物理块的数量,然后除以总的物理块的数量,得到已经使用的磁盘空间所占的百分比。这个百分比就是进度条的值,它反映了磁盘的剩余空间。
四、用户界面设计
用户界面采用 Qt 库实现,界面设计简洁直观,以下是程序运行时的截图:
4.1 整体界面
4.1.1 主界面
4.1.2 右键菜单
4.1.3 文本编辑界面
4.2 功能点界面展示
4.2.1 初始状态
4.2.2 格式化
4.2.3 删除子目录
4.2.4 显示目录
4.2.5 更改当前目录
4.2.6 创建文件
4.2.7 打开文件
4.2.8 关闭文件
4.2.9 写文件
4.2.10 读文件
4.2.11 删除文件
4.2.12 显示属性
4.2.13 修改图形大小
4.2.14 操作写入磁盘
4.2.15 重命名
五、总结
5.1 心得体会
在完成这个项目的过程中,我深刻地理解了文件系统的工作原理,包括文件存储空间管理、空闲空间管理以及多级目录结构等核心概念。通过编写代码模拟真实的文件系统,我不仅提升了自己的编程技能,也更深入地理解了操作系统中的文件系统部分。我发现,理论知识和实践操作是相辅相成的。理论知识为我提供了指导,而实践操作则使我能够将这些理论知识应用到具体的问题中去。同时,通过解决实际问题,我也能够更深入地理解和掌握这些理论知识。
此外,我也意识到了良好的编程习惯的重要性。在编写代码的过程中,我尽量保持代码的整洁和规范,这不仅使我能够更快地完成项目,也使得我的代码更易于理解和维护。
总的来说,这个项目是一次非常宝贵的学习经历。我不仅提升了自己的技能,也对文件系统有了更深入的理解。我期待在未来的学习和工作中,能够应用这些知识和技能,解决更多的实际问题。
5.2 改进方向
本项目的UI界面设计尽量与Windows11的设计相靠拢,对比之下便可以得知本项目还可以在以下方面进行功能扩充与改进:
- 继续美化UI,引入更多更丰富的图标。
- 加入更加丰富的功能: 复制、粘贴、打开方式、查看(列表、平铺、详细信息等)、撤销移动等等 加入足够多的快捷键,以便有更加丝滑的体验(如按下回车文件打开,Ctrl+S文件保存等等)
Reference
- 作者:王大卫
- 链接:https://tangly1024.com/article/homework:os-lab3
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。