期末实践:构建多用户二级文件系统
写在最前面
期末实验不是python写的,所以很可能是当时在github上找了一个,然后改了改hhh
如果后续找到了链接就放过来
问题描述
设计一个多用户的二级文件系统,能够实现简单的文件操作。具体包括如下几条命令:
(1)Dir 列文件目录; (2)Create 创建文件
(3)Delete 删除文件 (4)Deldir 删除目录
(5)Open 打开文件
(6)Close 关闭文件
(7)Read、Write读写文件
(8)Search 查询文件
(9)Copy 拷贝文件
(10)Cut 剪切文件。
要 求:
本课程设计要求按照学校有关规范的要求完成,在课程设计完成后需要提交的成果和有关文档资料包括期末实验测试报告,同时检查源程序及可运行程序(含运行环境)并打分。其中期末实验测试报告格式参考此文档格式完成,其内容不能过于简单。必须包括的内容有:
(1)功能设计部分:
1)课程设计的基本思想,系统的总体结构和各子模块的功能说明;
2)课程设计有关算法的描述,并画出有关算法流程图。
(2)源程序:源程序中核心代码及说明。源代码要求在关键的位置有注释,增加程序的可读性。程序结构和变量等命名必须符合有关软件开发的技术规范。
(3)程序运行结果
(4)心得与体会。即本课程设计的个人总结,主要包括以下内容:
1)课程设计中遇到的主要问题和解决方法;
2)你的创新和得意之处;
3)设计中存在的不足及改进的设想;
4)本次课程设计的感想和心得体会。
1 功能设计
文件系统是操作系统中负责管理和存取文件信息的软件机构,它由管理文件所需的数据结构(如目录表、文件控制块、存储分配表)、相应的管理软件、以及访问文件的一组操作所组成,是对文件存储器的存储空间进行组织、分配、负责文件的存储并对存入的文件进行保护、检索的系统。
1.1 系统层次结构
磁盘管理:系统最底层直接对内存空间的管理,如磁盘空闲空间管理,磁盘空间的分配方式等。
文件管理:系统对于文件和目录层次的管理的,规定了FCB结构,目录结构等,包含了对接口的实现。
系统接口: 该文件系统提供给前端可以使用的接口。
前端页面:文件系统呈现给用户的可视化界面。
1.2初始化
磁盘的逻辑单元为块,内存和磁盘之间的I/O传输以块为单位执行。基于磁盘的特点功能需要:1.可以原地重写,可以从磁盘上读一块儿,修改该块,并将它写回到原来的位置;2.可以直接访问磁盘上的任意一块。因此,可以方便地按顺序或随机访问文件。
(1)存储空间
文件系统首先要解决的问题,是有效分配文件存储器的存储空间。文件存储器的物理空间以块为单位进行分配。
磁盘大小:一共有10块磁盘块,每块磁盘块的大小为32*32=1024字节,磁盘块从0编号到9。
分配方式:显式链接,即通过存储文件分配表(File Allocation Table,FAT)。
每个磁盘的开始部分用于FAT,表中每个磁盘块都有一个FAT条目,并可通过块号索引。(未使用的块为0,使用的块包含下一个块儿号)。目录条目含有文件首块号码,通过这个块号索引的FAT条目包含文件下一块的号码,这个链会继续下去,直到最后一块,最后一块的表条目值为文件结束值。其优点为没有磁盘空间浪费,缺点是1.不支持文件的直接访问;2.需要更多的磁盘空间(来记录指针)。
(2)空闲空间
空闲空间表实现为位图,或位向量,标记了磁盘上所有盘块的使用情况。每块用一位(bit)表示,1表示块空闲;0表示块已分配。然后将所有空闲块用链表链接起来,并将指向第一个空闲块儿的指针保存在特殊位置,每个磁盘块含有下一个磁盘块的指针。
(3)文件的组织结构
文件系统第二个要解决的问题,是提供一种组织数据的方式。文件系统负责实现用户看到的逻辑特性,到物理特性的转换,实质是对“按名存取”功能的实现。
存储空间的管理。文件的逻辑结构有两种形式:一是无结构的流式文件,二是有结构的记录式文件。本次实验中采用的是流式文件的显示链接的物理文件结构,在每一个磁盘都创建了一个文件BitMap&&Fat.txt,记录了所有文件所占用内存块的情况,及对应内存块的位置。磁盘有多少块,文件分配表就有多少项,若某文件的一个磁盘块号为i,则这个文件的下一个磁盘的块号应该记录在文件分配表第i项。每个文件的FAT包含该文件的许多详细信息。他有一个唯一的标识号,以便与目录条目相关联。
分配磁盘块的流程图:
(4)文件的存储方法
文件系统第三个要解决的问题,是提供合适的存取方法,以适应各种不同的应用。设计文件控制块(FCB)包含有关文件的信息,包括所有者、权限、文件内容的位置等。设计目录实现方法为哈希表,根据文件名得到一个值,并返回一个指向线性列表中元素的指针。其优点为能减少目录搜索时间,缺点为两个文件名哈希到相同的位置时可能发生冲突;因哈希表固定大小,创建文件需要哈希表重建时,比较麻烦。
1.2 子功能设计
文件系统应提供一组服务,使用户能处理数据以执行所需要的操作,有两个不同的设计问题,一是访问问题:如何定义文件系统对用户的接口;二是存储问题:创建数据结构和算法,把逻辑文件系统映射到物理外存设备。
(1)选择系统于本机操作的文件夹
使用文件导航窗口FileChooser,实现点击上传文件时弹出一个框选择上传的文件。
(2)创建一个新的文件
应用程序调用逻辑文件系统。逻辑文件系统指导目录结构的格式,它会分配一个新的FCB。然后系统将相应的目录信息读入内存,更新目录结构和FCB,将结果写回磁盘。
系统调用open()将文件名传到逻辑文件系统,首先搜索整个系统的打开文件表,查看是否已经被打开,如果是,则在该进程的打开文件表创建一个条目,并指向现有整个系统的打开文件表。否则,根据文件名搜索目录结构。找到后,它的FCB会复制到内存的整个系统的开放文件表中(该表还存放着打开该文件的进程数量),接下来,在该进程的打开文件表创建一个条目,并指向现有整个系统的打开文件表。Open() 返回值:打开文件表的索引值,指向系统范围内打开文件表相应条目。
(3)删除文件、写文件、展示目录下所有文件
查找文件在当前目录的目录项描述内容,若存在则得到FCB的描述内容,释放FCB空间和文件数据空间,从目录表中删除文件的目录项。
根据FAT号找到要写回的区域,之前读入的部分中FCB进行调整,然后写覆盖。
对目录表进行遍历,同时根据文件类型做出不同的输出。
(4)目录的创建、删除及格式化
目录的创建和删除与文件的操作大致相同。
建立目录首先要找到建立目录的位置(父目录),然后查找该目录是否存在,如果父目录不存在,不能建立;如果存在,查找是否存在同名目录,存在,不能建立;不存在,则查找一个空目录项,为该目录申请一个盘块,并填写目录内容。注意,创建目录时目录表项的startBlock,不是FCB而是指目录的存放位置,而且还要自动为其添加多一个父目录项“…”,用于跳转。
格式化目录时,递归删除当前目录下的所有文件和目录。
(5)DFS算法查找文件|文件夹
深度优先搜索在搜索过程中访问文件目录后,递归地访问此目录的所有未访问过的相邻文件名,并判断当前文件|文件夹的名称是否与搜索的文件夹名称一致,如果不一致则继续访问。如果所有邻接结点(文件|文件夹)往下都访问过了,就回溯到更上一层(文件夹)。如果访问全部后依然没有找到,返回-1。
2 源程序
2.1 系统实现主要的软件技术
在功能设计的基础上,确认项目大体框架。
2.2 数据结构
这里仅展示磁盘Block板块的核心。
public class Block { private int blockName; // 名称 private File blockFile; // 盘区内的文件 private File blockBitMap; // 位图存储文件 private File recover; // 恢复文件 private FileWriter bitWriter; // 位图存储文件书写器 private FileWriter recoverWriter; // 恢复文件书写器 private int fileNum; // 文件数量 private double space; // 盘区已占用空间 public int [][] bitmap = new int[32][32]; // 内存块数组 private Map<String, int[][] > filesBit = new HashMap<String, int[][]>(); // 文件和内存块对应表 private ArrayList<File> files = new ArrayList<File>(); // 文件列表 public Block(int name, File file, boolean rec) throws IOException { // 初始化} public File getBlockFile(){ return blockFile;} public void putFCB(File file, double capacity) throws IOException { // 将FCB写入文件} public void rewriteBitMap() throws IOException { // 重写位图存储文件} public void rewriteRecoverWriter() throws IOException{ // 重写恢复文件} public boolean createFile(File file, double capacity) throws IOException { // 在盘区内创建文件} public boolean deleteFile(File file, double capacity){ // 在盘区内删除文件} public boolean renameFile(File file, String name, double capacity) throws IOException { // 重命名盘区内的文件} public int getFileNum() { return fileNum;} public double getSpace() { return space;} }
2.3 后端
(1)创建工作区
rootFile = new File(rootPath + File.separator + "myFileSystem"); readMe = new File(rootPath + File.separator + "myFileSystem" + File.separator + "ReadMe.txt"); boolean flag = true;
(2)文件树
位于左侧,呈现文件的目录结构,详情见目录结构。
并在文件ReadMe.txt中,写入创建的磁盘块信息。
final DefaultMutableTreeNode root = new DefaultMutableTreeNode(new fileSystem2.myFiles(rootFile, 0, 10240)); if (!rootFile.exists()) { flag = false; try { rootFile.mkdir(); readMe.createNewFile(); } catch (Exception e) { JOptionPane.showMessageDialog(null, "当前位置不支持创建目录!", "Error", JOptionPane.ERROR_MESSAGE); System.exit(0); } FileWriter writer = new FileWriter(readMe.getPath()); writer.write("this my fileSystem2\n"); writer.write("Space: 10 * 1024K = 10M\n"); writer.write("Free-Space Management:bitmap\n"); writer.write("Store-Space Management:FAT\n"); writer.flush(); writer.close(); } root.add(new DefaultMutableTreeNode(new fileSystem2.myFiles(readMe, 0, 0))); model.addRow(new fileSystem2.myFiles(readMe, 0, 0));
(3)创建磁盘块
一共创建10个磁盘块,以磁盘1为例。
block1 = new Block(1, new File(rootFile.getPath() + File.separator + "1"), flag); blocks.add(block1); root.add(new DefaultMutableTreeNode(new fileSystem2.myFiles(block1.getBlockFile(), 1, 1024.0))); model.addRow(new fileSystem2.myFiles(block1.getBlockFile(), 1, 1024.0)); ((DefaultMutableTreeNode)root.getChildAt(0)).add(new DefaultMutableTreeNode("temp"));
(4)获取文件存储空间大小
public double getSpace(File file){ double space = 0; try { BufferedReader reader = new BufferedReader(new FileReader(file)); reader.readLine(); space = Double.parseDouble(reader.readLine()); if (space > 1024){ space = 0.0; } reader.close(); } catch (Exception e){}; return space; }
(5)更新块信息
public void upDateBlock(Block currentBlock){ fileNumField.setText(String.valueOf(currentBlock.getFileNum())); usedField.setText(String.valueOf(currentBlock.getSpace()) + " KB"); freeField.setText(String.valueOf(1024 - currentBlock.getSpace()) + "KB"); }
(6)将创建的工作区信息放入FCB文件中
public void putFCB(File file, double capacity) throws IOException { FileWriter newFileWriter = new FileWriter(file); newFileWriter.write("File\r\n"); newFileWriter.write(String.valueOf(capacity) + "\r\n"); newFileWriter.write("Name: " + file.getName() + "\r\n"); newFileWriter.write("Path: " + file.getPath() + "\r\n"); String ctime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date(file.lastModified())); newFileWriter.write("Date last updated: " + ctime + "\r\n"); newFileWriter.write("--------------------------edit file blew ------------------------------\r\n"); newFileWriter.close(); }
(7)删除当前目录
public static void deleteDirectory(String filePath){ File file = new File(filePath); if(!file.exists()){ return; } if(file.isFile()){ file.delete(); }else if(file.isDirectory()){ File[] files = file.listFiles(); for (File myfile : files) { deleteDirectory(filePath + File.separator + myfile.getName()); } file.delete(); } }
(8)创建文件
通过调用File类的createFile()方法来实现。除了创建文件本身外,还使用了一串0和1来标识内存块的状态,以生成FCB文件。0为未使用,1表示已经被占用。创建文件时从最前方开始检索空闲块,确定使用后将0置为1。注意:文本中将自动生成FCB,不支持自行修改FCB。
文件创建成功之后,将刷新FAT和位图。如果存储空间不足或是输入非法将导致文件生成失败。
public boolean createFile(File file, double capacity) throws IOException { files.add(file); file.createNewFile(); int cap[][] = new int[32][32]; for (int i = 0; i < 32; i++){ for (int k = 0; k < 32; k++) cap[i][k] = 0; } if (count > 0){ JOptionPane.showMessageDialog(null, "内存不足!", "Fail", JOptionPane.ERROR_MESSAGE); file.delete(); for (int i = 0; i < 32; i++){ for (int k = 0; k < 32; k++){ if (cap[i][k] == 1){ bitmap[i][k] = 0; } } } return false; }else{ fileNum++; space += capacity; filesBit.put(file.getName(), cap); rewriteBitMap(); rewriteRecoverWriter(); putFCB(file, capacity); // Put FCB上一篇: 理解进程及其间的交流机制
下一篇: 理解进程间通信(IPC)的基本概念
推荐阅读
-
openEuler郑州用户组成立!openEuler与hyperfusion携手共建河南地区用户生态 - 开幕致辞 超融合操作系统业务总经理、openEuler委员会成员蒋振华先生为本次活动致辞。 在本次活动的致辞中,他提到,作为openEuler社区早期的成员,超融合见证了openEuler从成立到在各行业商业落地,再到跨越生态拐点的过程,感谢openEuler提供了一个全产业链共同创新的平台,共同推动创新技术的商业落地。 同时,本次活动得到了郑州市郑东新区大数据管理局、郑州中原科技城投资服务局的大力支持。 郑东新区大数据管理局曹光远 在活动致辞中表示,openEuler的应用和*应用设施的深度优化,为郑东新区数字化转型提供了安全、可靠、高性能的技术基础;郑州中原科技城招商服务局王林表示,郑东新区欢迎所有openEuler生态相关企业扎根当地,围绕openEuler社区共同发展,形成合力。 openEuler社区及运维功能介绍 openEuler技术委员会委员胡峰 openEuler技术委员会委员胡峰先生在本次活动中介绍了openEuler社区目前发展的整体情况,并重点从技术层面介绍了openEuler的运维功能。 openEuler 晚会 胡峰先生介绍智能运维工具 A-Ops 和 openEuler gala、 阿波罗 Apollo、智能漏洞管理解决方案等新功能,以及涵盖各种运维场景的精品运维组件。在*交流环节,许多用户就目前使用的 openEuler 在*交流环节,许多用户就自己在使用openEuler过程中遇到的一些问题与胡峰先生进行了进一步的交流。 软硬结合,构建多样化算力操作系统 Hyperfusion 基于 openEuler 的基础上,结合自身软硬件技术积累,推出了富讯服务器操作系统 FusionOS FusionOS. FusionOS 首席架构师张海亮 分享了 FusionOS FusionOS首席架构师张海亮分享了FusionOS的软硬件协同优势、卓越的性能和可靠性,以及FusionOS在金融、运营商、*、互联网等行业的实践案例,引起了众多用户的兴趣,分享结束后,不少参会者就FusionOS的特点向讲师提问并进行了交流。
-
理解域名层次:一级域、二级域与三级域的区别与应用" "*域名、主域名、子域名详解:对SEO的影响及使用决策" "搭建网站时:二级域名与子目录的选择指南" "详解如何在*域下设置Apache的二级域名" "初学者必读:挑选理想域名的五大关键建议" "构建网站时,一级域名与二级域名的实践配置教程
-
期末实践:构建多用户二级文件系统