JAVA实现UNIX文件管理系统

       这个项目是操作系统的期末课设,正好最近在学java,于是就试着拿java写了一个,基本功能也都实现了界面效果也还可以,发出来大家让大家指点一下。另外,第一次发博客,还请各位大神轻喷。

一、UNIX文件系统的基本原理

       UNIX采用树型目录结构,每个目录表称为一个目录文件。一个目录文件是由目录项组成的。每个目录项包含16B,一个辅存磁盘块(512B)包含32个目录项。在目录项中,第1、2字节为相应文件的外存i节点号,是该文件的内部标识;后14B为文件名,是该文件的外部标识。所以,文件目录项记录了文件内、外部标识的对照关系。根据文件名可以找到辅存i节点号,由此便得到该文件的所有者、存取权、文件数据的地址健在等信息。UNIX的存储介质以512B为单位划分为块,从0开始直到最大容量并顺序加以编号就成了一个文件卷,也叫文件系统。本次课程设计是要实现一个简单的模拟UNIX文件系统。我们在磁盘中申请一个二进制文件模拟UNIX内存,依次初始化建立位示图区,I节点区,数据块区。

二、基本要点思路 

       1、模拟磁盘块的实现:因为文件系统需要从磁盘中读取数据操作数据,在实现时是使用文件来模拟磁盘,一个文件是一块磁盘,在文件中以划分磁盘块那样划分不同的区域,主要有三个区域:位图区,inode索引节点区,磁盘块区。位图区我是使用一个512byte的数组存放,inode区和磁盘块区我采用一种自认为比较巧妙的方法,就是存放对象列表,之前说过,在本次实验的所有的结构都使用对象进行存储,而inode节点和磁盘块就是两个重要的数据结构,在初始化时我实例化32个inode对象和512个block对象(至于这些类的具体定义下面会提到),然后将这些对象加入各自对应的对象列表中,在存储时,使用java的对象序列化技术将这个对象数组存到磁盘中。当使用文件系统时,程序会先从磁盘文件中读取出位图数组,inode对象列表,block对象列表,之后的操作就是通过对这些列表进行修改来实现。使用这种方法可以减小存储的空间(对象序列话技术)而且不需要在使用时进行无用的查找,只要第一次初始化中将这些对象都读取出来。

       2、界面的实现:在实现这个文件系统时使用了两种方案,一种是直接在java控制台来进行输入输出,因为原本想着UNIX文件系统原本也是使用的命令行语句,所以在控制台上实现也很接近。后来在老师的建议下又将整个程序重新修改,改成在UI界面上进行输入输出,这样确实界面美观舒服了不少,只不过两者用的技术很不一样,前者主要使用的是系统的输入输出流,后者使用java监听器。

       3、权限的实现:在实现多用户的权限方面,我给文件和文件夹各定义了三级权限1、访问:在文件中是可以查看文件的内容,在文件夹中是可以进入该文件夹。2、修改:文件中是可以对文件进行编辑,文件夹中是可以在该文件夹中创建新的文件或目录。3、删除:顾名思义。文件或文件夹的创建者拥有最高级别的权限,只有拥有最高级权限的用户才可以给其他用户针对该文件或文件夹进行授权和授权操作。在每次对文件或文件夹进行访问修改删除操作时都会检查当前用户在该文件或文件夹所拥有的权限,只有拥有的权限大于想要实现的权限时才可以进行该操作。

三、各个方法的详细介绍

      1、format模块

      功能:格式化文件系统,即初始化文件系统,相当于硬盘的格式化。将其中原有的用户及用户下的文件系统全部还原初始状态,即没有任何用户和目录、文件,也就是按设计的文件系统格式重建新的文件系统。

      实现方法:将所有位图区全置为不可用,inode和block结点列表中已修改的对象置空。

      2、LoginUI()模块

      功能:登录的UI界面

      实现方法:创建一个有可输入用户信息的dialog提示框,为按钮添加监听器,可读取用户信息文件的内容并对用户身份进行判断,若成功则调用initUI()方法进入主UI界面,并且对程序中的user属性赋值,失败则重新调用本方法

      3、loginOutUI()模块

      功能:退出登录的界面

      实现方法:将程序中的user属性赋为空值,重新调用loginUI()方法。

      4、init()模块

      功能:读入文件系统

      实现方法:从文件中读出位图数组,inode结点列表和block列表并对自身的相应属性进行赋值

      5、switchCommend()模块

      功能:根据命令行指令调用相应的函数

      实现方法:因为命令行指令每个指令都是由两部分组成,命令指令和操作对象,可以使用java的split方法根据空格将其隔开生成两个子串,根据第一个选择调用的方法第二个子串作为参数传递。

      6、help()模块

      功能:显示帮助信息

      实现方法:字符串

      7、ls()模块

     功能:显示当前目录下的文件和文件夹信息

     实现方法:遍历inode结点列表,找到其parent值为当前目录索引号的结点,显示其名称,并根据该结点的type进行判断,若是目录,显示名称之前加一个点。

     8、clear()模块

     功能:情况屏幕

     实现方法:清空输出文本域

     9、quit()模块

    功能:退出文件系统并保存对其做的修改。

    实现方法:删除原磁盘文件的内容并重新写入

    10、vi()模块

    功能:将打开文件和创建文件合为一体(模仿vim命令行)。

    实现方法:若当前目录中没有指定文件则调用createfile()方法创建新文件,若有,则先调用checkgrant()方法检查授权,若有授权则调用read()方法读取文件

    11、read()模块

    功能:读取文件在磁盘块中的信息

    实现方法:根据索引结点得到其磁盘块索引,并找到对应的磁盘块提取出信息,传入readUI()中显示。

    12、readUI()模块

    功能:显示文件内容

    实现方法:将传入的字符串显示在输出文本域,设置一个编辑按钮并添加监听器,点击后首先调用checkgrant()检查权限,若有权限则进行文本编辑,编辑完成后将编辑后的内容进行保存。这里是最重要的一块,在保存时首先应将文件原本的内容提取出来,将原磁盘块置空并记录下原磁盘块索引,然后将编辑的文本追加上去,算出新文本所需磁盘块数量,若大于原磁盘块数量,则先将原磁盘块写满再从位图区读出空虚磁盘块进行填写,若小于,则先将元磁盘块填些。(这点逻辑花了很久才考虑出来并且完善)

    13、createfile()模块

    功能:创建新文件

    实现方法:在索引结点中根据IsAvaliable属性找到可用inode结点,实例化 一个新对象将其替换,并将其IsAvailable属性置为false。然后进入调用readUI方法。

    14、delete()模块

    功能:删除文件

    实现方法:遍历inode结点列表,根据文件名和当前文件夹编号找到对应结点,先调用grantcheck方法检查权限,若有权限则将该inode结点置空,记录下磁盘块索引,调用delete_block方法删除磁盘块信息。

    15、delete_block()模块

    功能:删除磁盘块内容。

    实现方法:根据磁盘块索引找到对应磁盘块置空

    16、cd()

     功能:将当前目录切换到当前目录的一个子目录下或当前目录的父目录。

    实现方法:遍历inode结点列表,根据文件名和当前目录索引号找到对应结点,检查权限后将当前目录索引号替换成该文件夹的索引号。

    17、mkdir()模块

    功能:创建新的文件夹

    实现方法:检查权限后从inode结点去根据IsAvailiable属性找到可用结点,将其实例化新结点给IsAvailable赋false并替换。

    18、rd()模块

    功能:删除文件夹及其中的文件及文件夹

    实现方法::遍历inode结点列表,根据文件名和当前目录索引号找到对应结点,检查权限后将其置空,并记录下结点索引号,递归删除所有文件及文件夹。

     19、grantUI()模块

     功能:对指定文件或文件夹给用户赋予权限

    实现:遍历inode结点列表,根据文件名和当前目录索引号找到对应结点,检查权限后将用户名和对应的赋予权限记录在该inode结点的grantmap属性中(权限在之后会有介绍)

     20、regrantUI()模块

     功能:对指定文件或文件夹收回某个用户的权限

     实现:遍历inode结点列表,根据文件名和当前目录索引号找到对应结点,检查权限后将用户名和对应的权限在该inode结点中的grantmap属性中删除。

     21、showcur()模块

    功能:模仿UNIX文件系统命令行的前缀。

    实现方法:根据inode结点的iparent属性,从当前文件夹结点开始循环找其上一级结点名称并输出。

    22、showmap()模块

    功能:显示磁盘块使用情况

    实现方法:输出位图数组

    23、showfileMessage()模块

    功能:显示文件信息

    实现方法:遍历inode结点列表,找到可用结点并输出其名称,用户权限等信息

    24、print/println()模块

    功能:将输出信息显示在UI界面上

    实现方法:用JTextArea的append方法为文本域添加信息

    25、checkgrant()方法

    功能:检查权限信息

    实现方法:根据文件名称和当前文件夹索引找到inode结点,遍历其权限列表,查看当前用户及想要实现的功能是否符合权限。

 

总结

       这个项目的一个特点就是在模拟磁盘存储时使用了对象代替结点、磁盘块,列表代替存储区域,文件代替存储空间的做法,节省空间,操作简单。

       在写代码时也走了很多弯路,有好几次因为一个小小的错误而整晚排bug,现在想起来也是很痛苦,但同时收获也是巨大的,不仅对文件系统的底层原理产生了非常深入的理解,对java编程方面也有了很大的进步与提升,在排除bug的过程也非常考验我的逻辑思维能力,必须有着清醒的头脑,对逻辑有着很深的了解才能快速排除bug。在写代码时遇到的困难也是巨大的,比如说在写磁盘块的写入写出的逻辑也是困扰了我很久,尝试了各种方法,先是试着每次写入都要开辟一个新的磁盘块,但是觉得那样太浪费空间,又试着在每次写入前先将之前的内容取出再和新的内容一块放入新磁盘块中,但这样又太浪费时间,在实际中也不可能会这样做,就这样试了各种方法后才找到现在的先将之前的磁盘块索引记下,然后再重新将新旧内容一起装入的方法,虽然看上去和之前的方法区别好像就那么一点,但是要从前者想到后者可是花了我很多时间。

       另外一个很大的挑战就是从控制台转到UI界面,原本想着仿照UNIX系统的命令行的话,他本来就是在它的控制台中进行输入输出,所以我就直接在java的控制台来进行文件系统的所有操作了。但是听从老师的建议还是改成在UI界面上输出,原本以为会很简单地改好,只是将输出的语句换成显示在文本框。但是实际操作起来才发现和自己想的完全不一样。因为在控制台输出时java调用系统的输入流来获取我的输入信息,所有都在一个线程中进行操作,所以当我要输出时程序会等待我的输入,获取我的输入信息后来进行下一步的操作,但是使用UI界面后,UI界面和主程序是两个线程,这时当遇到程序需要我的输入作为下面步骤的参数的操作时主线程不会等我在UI界面输入后才进行下一步,而是直接进行到需要我指令的步骤,这是就只能报空指针异常。为解决这个方法我考虑了一整个晚上都没有解决的方法,都已经接近绝望了,最后没办法只能进行大改,一个函数一个函数地开始该,将没个需要我指令才能进行操作的语句都放到UI界面的监听器里完成,确保这些指令都在一个线程里执行,这样就不会出现错乱的现象,就这样全部改下来像是重新写了一遍这个程序。不过也多亏这重新写一遍,让我发现了很多之前为发现的bug和可以简化的步骤。

       还有一个就是教训就是自己的考虑不周,在权限方面,原本没考虑那么多,只是把权限用简单的授权码进行区别,有授权码就是已授权,没有就是未授权,这种方法想也知道太过简单粗糙,完全是偷懒行为,在老师的提醒下才重新考虑这个问题,对权限进行分类分级划分,授权收权方式也更加具体合理。

源码

https://github.com/ZZYYG/myRepository这个是github的链接,刚开始系统学习编程,github里面也只有一个项目,希望大家多踩踩。

 

展开阅读全文

没有更多推荐了,返回首页