利用Java模拟实现磁盘阵列raid级别0、1、3、5、6、01、10

1.使用说明

本程序开发环境为Windows操作系统Eclipse软件,使用Java语言进行开发。使用时打开项目文件并运行raidMain包下面的Main.java根据提示输入要写入的文件(文件全路径)、读出的文件(输入的文件路径表示文件读出时保存的路径,包含要读出的文件名)、恢复文件即可。每个磁盘阵列级别的数据所使用的磁盘(文件夹)是不同的,例如raid0的的磁盘主路径为disk/raid0,raid6的为disk/raid6。另外的disk/read和disk/read是用来演示写入读出的文件路径,当然也可以选择其他的文件进行操作(没有完成raid3,5,6的磁盘损坏时的数据恢复,写到后面还是发现程序结构还是有很大问题,但是改动的化消耗的时间较多,就不了了之了)。

2.总体设计

磁盘利用文件夹进行模拟,存储的数据为任意类型的文件,文件条带数根据相应的存储盘数进行划分,有几个数据存储盘则划分为几份,且为了在读出文件时识别该文件块属于原文件当中的哪一块,方便进行重组,在文件名后添加该文件在原文件中的起始位置。程序入口Main.java类中可以利用通过输入命令选择相应的磁盘阵列,每个磁盘阵列的磁盘不共用,方便对文件进行管理。进入到相应的磁盘阵列进行至多四种功能,分别是写入文件至磁盘阵列中、从磁盘阵列中读出文件、磁盘阵列中的磁盘损坏时恢复数据、退出该磁盘阵列返回选择磁盘阵列菜单的功能。
在这里插入图片描述

3.运行截图

在这里插入图片描述

4.详细设计

raidMain包中的Main.java为程序入口类,其中的main方法中输出菜单项然后scanner输入选项利用switch-case结构判断使用哪一个raid级别并新建相应的类的对象的start方法同时还传入scanner对象用于获取控制台输入。若在另一个对象中新建scanner对象则此scanner对象会无法关闭,不关闭会有警告,关闭则另一个对象的scanner控制台输入则就会报错,且前后输入的数据类型应该保持统一,这里控制台读入均为string类型。输入非0-7的其他字符会提示输入正确指令并重新输入,若输入0则关闭输入流并退出程序。

4.1raid0

若输入1,进入raid0。在RAID0Main类的start方法中传入scanner对象,定义raid0所有磁盘所在的父路径,并利用file对象的list方法列出、逐个搜索该路径所有的磁盘,添加保存到arraylist对象中,然后再while循环中同样写出要执行的功能并利用switch-case结构进行判断,1写入磁盘阵列;2从磁盘阵列中读出数据;0退出返回上一级的主菜单选择磁盘阵列级别,输入其他则提示输入正确指令。
在这里插入图片描述

若输入1,则会要求输入要上传的文件路径并立用该路径创建file对象进行判断该文件是否存在,若不存在则提示文件不存在并直接跳出swtich-case结构;否则利用磁盘阵列的磁盘路径和上传的文件路径创建RAID0Write对象,并根据磁盘个数新建多线程进行数据写入。
RAID0Write为写入磁盘阵列的类,实现Runnable接口。构造函数中传入各个磁盘位置的arraylist对象和要写入的文件路径,并调用initialize函数进行初始化,初始化函数中主要是利用磁盘个数计算出和文件的字节长度计算每个磁盘的应存的文件字节长度,平均存取,多出的则放在最后一个盘中,同时还保存除最后一个文件条带的大小和最后一个文件条带的大小,并保存要写入的文件名和文件类型。
接着在线程run方法中,利用同步块将该类的变量保存赋给局部变量并加1,表示这个线程将数据写入磁盘变量对应的磁盘的下标。判断此磁盘是否是最后一个磁盘并设置并根据上面计算的文件条带长度得出本磁盘将要保存的文件条带长度。在此磁盘上新建文件条带文件的对象,同时为了数据的读出,在文件名后添加该文件条带在原文件当中的起始位置。若该文件存在则删除并新建。利用RandomAccessFile随机读取文件对象分别以读写形式打开原文件和目标文件,并利用该对象的方法seek设置读文件的位置。设置缓冲区大小为1kb,文件条带长度小于此则直接读取写入,否则利用循环读取直到剩余未读取的文件大小小于缓冲区长度,最后关闭随机读取文件对象即可。
若输入2,则要求输入要读出的文件路径,同时还分离出文件名和文件类型, 获取其中一个数据盘的所有文件名并和输入的文件名利用正则表达式进行比对看是否存在要读出的文件,如果不存在则退出switch-case循环,否则同样还是根据磁盘个数创建线程进行文件读取。
RAID0Read为文件读出的类,构造函数传入磁盘路径和读出的文件路径,并调用初始化函数,里面进行的操作基本和写入类的那部分一样。在run方法中利用同步块取地唯一的数字表示当前要读取的磁盘,在此磁盘中找到要读的文件名,然后根据找到的文件名得出该文件条带在原文件当中的位置,并利用随机读取文件对象的函数设置写入的文件的位置并开始读取文件条带并写入目标文件。

4.2raid1

若输入2,进入raid1。和上面重复的就不再说明,主要说明的是其思想,该raid级别多出的一个选项是文件恢复。,构造函数传入数据磁盘路径和空的备份盘路径。这里磁盘损坏表示的是文件夹不存在,先计算出磁盘损坏的个数,并将损坏的磁盘路径从磁盘路径变量中去掉。然后若损坏的磁盘个数为0则不需要恢复,若备份的空磁盘个数为0也不恢复,如果所有磁盘都已经损坏了则输出无法恢复的信息。除了以上的情况则进行数据恢复,也就是将不损坏的磁盘文件遍历并利用files.copy函数复制到新的数据盘,同时更新数据盘和备份空磁盘变量的路径信息。
数据写入磁盘还是根据磁盘个数启动多个线程,将文件直接复制到对应的磁盘当中即可。而读出文件就是将磁盘当中的第一个作为数据的读取迷人盘,遍历该盘找到该文件复制到指定路径即可,若第一个磁盘没有则到其他数据盘中读取文件,若所有数据盘都坏了则输出信息说明。
在这里插入图片描述

4.3raid3

若输入3,进入raid3。raid3的数据读取和raid1一样都是根据要读取的文件名找出各个文件条带并根据文件条带在原文件当中的位置进行写入目标文件即可。而写入基本流程和raid1还是一样,只不过这次还多出一个将各个文件条带的数据的奇偶校验和(异或操作)的数据写入一个奇偶校验磁盘。在读出要写入的文件数据时根据文件条带为单位将读出的字节数据暂时保存起来,待全部读取出来后,此时各个文件条带也写入对应的磁盘中了,然后将保存起来的数据逐组进行异或,最后一个文件条带的数据可能会多出,多出则直接拼接在该文件的奇偶校验文件的后面,并通过在文件名后添加拼接的起始位置记录哪些是异化哪些是直接拼接的数据。
至于如何保证奇偶校验码文件的生成在读取文件条带之后,主要是利用线程池,利用ExecutorService threadPool = Executors.newCachedThreadPool()初始化线程池,接着利用threadPool.submit()的方法以文件读对象作为形参提交到线程池,有几个数据盘则提交几个线程,threadPool.shutdown()执行完线程池里面的线程并关闭线程池,禁止提交新的线程,利用while循环不断判断threadPool.isTerminated线程池是否终止了,终止之后就可以执行生成奇偶校验码的文件。
在这里插入图片描述

4.4raid5

若输入4,进入raid5。raid5将所有文件的对应的奇偶校验码信息平均放在每个磁盘,因此思路还是和raid3差不多,在初始化磁盘路径时先指定任意一个为存放奇偶校验码的磁盘,其他为数据盘。在每往磁盘阵列写入一个文件,该文件的校验码信息写入此时的检验码磁盘,然后将该校验码磁盘所存的磁盘路径换成数据盘的第一个,再将换下来的路径添加到数据磁盘路径动态数组的末尾并删除第一个路径。相当于每个磁盘轮流做奇偶校验码。
在这里插入图片描述

4.5raid6

若输入5,进入raid6。raid6和raid5的区别就是在前者有两个磁盘上存同一种或不同类型的校验码文件,这里都是利用奇偶校验码。读出数据和raid5是一样的,遍历所有磁盘的文件找到所要读出的文件重新组合起来即可。对于磁盘阵列的写入, 其他思路是一样的,只不过是在开始时给奇偶校验码磁盘数位2,然后每次写入文件把校验码信息写入这两个磁盘,然后将这两个磁盘移到数据盘的动态数组,数据盘再轮流的将两个作为校验码存放盘作为下个文件存入的校验码存放位置,如此循环反复。
在这里插入图片描述

4.6raid01

若输入6,进入raid01。该磁盘阵列的的磁盘路径分为raid0磁盘路径(每个文件的文件条带个数)、raid1磁盘路径(也就是前者的复制,数量是前者的整数倍,表示复制了几份)、还有就是用于恢复数据的备份盘。这里还是利用多线程,分别利用raid0和raid1的思路,先将文件分成raid0磁盘个数的份数并分别存放,然后再将分好的文件条带逐个复制到raid1磁盘上即可,文件条带的存放顺序和raid0上的磁盘一样。而在读出时,和raid0一样将raid0磁盘上的数据读出,若损坏,则自动从raid1磁盘上进行读取。
恢复文件时的思路就是从各个磁盘上,从raid0磁盘开始,先找到能组成完成原文件的文件条带的文件对象保存起来,若某一块的数据已经完全找不到了,则输出相应的信息。找到之后然后再遍历一遍所有磁盘找到损坏的磁盘,利用备份的空磁盘上替换该坏掉的磁盘,并将原磁盘上村存储的数据恢复到该新的数据磁盘上。
在这里插入图片描述

4.7raid10

若输入7,进入raid10。raid10由于是先复制然后再文件分带,但是再写的时候我是认为这样相比与raid01的先分带再复制是不好的,效率是底下的,所以我认为当前写这种程序没有任何意义,因此还是按照raid01的思路来写,只不过是磁盘阵列存储的策略上有所区别。所有数据磁盘的路径存储在二维动态数组中,一维数表示raid0的盘数(数据分为几份),二维数表示raid1的盘数(复制几份),再写入时先将根据二维盘数所分好的文件条带存储到二维的磁盘的第一个,然后将分好的文件条带在同组的磁盘中进行复制即可。读和恢复思路和raid01基本一致,就不再赘述。
在这里插入图片描述

5.源码

https://gitee.com/zhuhezhang/raid
https://github.com/zhuhezhang/raid

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值