这是我前段时间做了一个操作系统课程设计作业,使用java实现了命令行输入对虚拟文件进行管理。
下面是课程设计要求:
题目五 模拟磁盘文件系统实现
一、课程设计目的
了解磁盘文件系统的结构、功能和实现。并可练习合作完成系统的团队精神和提高
程序设计能力。
二、小组人数 建议 3~5 人一组共同完成模拟磁盘文件系统的实现。 选择题目“模拟磁盘文件系统实现”的小组在最终提交时须公开演示及讲解。 由于这个题目较复杂,难度和工作量远大于前面几个题目,故小组成员最后得分 也酌情高于选择前面四个题目的同学的分数(高 5~10 分)。 三、编程语言
建议使用一些 Windows 环境下的程序设计语言如 VC、Java,以借助这些语言的多
线程来模拟并行发生的行为。要求图形界面。
四、课程设计内容
设计一个简单的文件系统,用文件模拟磁盘,用数组模拟缓冲区,要求:
(1) 支持多级目录结构,支持文件的绝对读路径;
(2) 文件的逻辑结构采用流式结构,物理结构采用链接结构中的显式链接方式;
(3) 采用文件分配表 FAT;
(4) 实现的命令包括建立目录、列目录、删除空目录、建立文件、删除文件、显示
文件内容、打开文件、读文件、写文件、关闭文件、改变文件属性。可以采用
命令行界面执行这些命令,也可以采用“右击快捷菜单选择”方式执行命令。
(5) 后编写主函数对所作工作进行测试。
下面是我实现的功能:
以下为源代码
首先是一个FileModel类用来记录文件或目录的相关属性
package com.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class FileModel {
public Map<String, FileModel> subMap = new HashMap<String, FileModel>();
private String name; //文件名或目录名
private String type; //文件类型
private int attr; //用来识别是文件还是目录
private int startNum; //在FAT表中起始位置
private int size; //文件的大小
private FileModel father = null; //该文件或目录的上级目录
public FileModel(String name, String type, int startNum, int size){
this.name = name;
this.type = type;
this.attr = 2;
this.startNum = startNum;
this.size = size;
}
public FileModel(String name, int startNum) {
this.name = name;
this.attr = 3;
this.startNum = startNum;
this.type = " ";
this.size = 1;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getAttr() {
return attr;
}
public void setAttr(int attr) {
this.attr = attr;
}
public int getStartNum() {
return startNum;
}
public void setStartNum(int startNum) {
this.startNum = startNum;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public FileModel getFather() {
return father;
}
public void setFather(FileModel father) {
this.father = father;
}
}
package com.service;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.model.FileModel;
import com.sun.xml.internal.bind.v2.util.FatalAdapter;
public class OSManager {
public Map<String, FileModel> totalFiles = new HashMap<String, FileModel>();
//定义FAT表
private int[] fat = new int[128];
//创建根目录 使用fat表的第一项
private FileModel root = new FileModel("root", 1);
private FileModel nowCatalog = root;
public OSManager() {
// TODO Auto-generated consructor stub
//将FAT表初始化全部为0,并将第一位设为根目录的空间
for(int i=0; i<fat.length ; i++ ) {
fat[i] = 0;
}
fat[1] = 255; //255表示磁盘块已占用
fat[0] = 126; //纪录磁盘剩余块数
root.setFather(root);
totalFiles.put("root", root);
}
public int setFat(int size) {
int[] startNum = new int[128];
int i = 2; //纪录fat循环定位
for(int j=0; j<size; i++) {
if(fat[i] == 0) {
startNum[j] = i; //纪录该文件所有磁盘块
if(j>0) {
fat[startNum[j-1]] = i; //fat上一磁盘块指向下一磁盘块地址
}
j++;
}
}
fat[i-1] = 255;
return startNum[0]; //返回该文件起始块盘号
}
/*
*
* 该方法用于删除时释放FAT表的空间
*/
public void delFat(int startNum) {
int nextPoint = fat[startNum];
int nowPoint = startNum;
int count = 0;
while(fat[nowPoint] != 0) {
nextPoint = fat[nowPoint];
if(nextPoint == 255) {
fat[nowPoint] =0;
count++;
break;
} else {
fat[nowPoint] = 0;
count++;
nowPoint = nextPoint;
}
}
fat[0] += count;
}
/*
*
* 以下为追加内容时修改fat表
*
*/
public void reAddFat(int startNum, int addSize) {
int nowPoint = startNum;
int nextPoint = fat[startNum];
while(fat[nowPoint] != 255) {
nowPoint = nextPoint;
nextPoint = fat[nowPoint];
}//找到该文件终结盘块
for(int i=2, count = 0; count <addSize ; i++ ) {
if(fat[i] == 0) {
fat[nowPoint] = i;
nowPoint = i;
count++;
fat[nowPoint] = 255;//作为当前文件终结盘块
}
}
}
/*
* 以下为创建文件和目录方法
* 14R5黎志亮
*/
public void createFile(String name, String type, int size) {
if(fat[0] >= size) { //判断磁盘剩余空间是否足够建立文件
FileModel value = nowCatalog.subMap.get(name); //该目录下是否寻找同名目录或文件
if(value != null) { //判断该文件是否存在
if(value.getAttr() == 3) { //若存在同名目录 继续创建文件
int startNum = setFat(size);
FileModel file = new FileModel(name, type, startNum, size);
file.setFather(nowCatalog); //纪录上一层目录
nowCatalog.subMap.put(name, file); //在父目录添加该文件
totalFiles.put(file.getName(), file);
fat[0] -= size;
System.out.println("创建文件成功!");
showFile();
} else if(value.getAttr() == 2) { //若同名文件已存在,创建失败
System.out.println("创建失败,该文件已存在!");
showFile();
}
} else if(value == null) { //若无同名文件或文件夹,继续创建文件
int startNum = setFat(size);
FileModel file = new FileModel(name, type, startNum, size);
file.setFather(nowCatalog); //纪录上一层目录
nowCatalog.subMap.put(name, file); //在父目录添加该文件
totalFiles.put(file.getName(), file);
fat[0] -= size;
System.out.println("创建文件成功!");
showFile();
}
} else {
System.out.println("创建文件失败,磁盘空间不足!");
}
}
public void createCatolog(String name) {
if(fat[0] >= 1) { //判断磁盘空间是否足够创建文件夹
FileModel value = nowCatalog.subMap.get(name); //判断该目录下是否存在同名目录或文件
if(value != null) {
if(value.getAttr() == 2) {
int startNum = setFat(1);
FileModel catalog = new FileModel(name, startNum);
catalog.setFather(nowCatalog); //纪录上一层目录
nowCatalog.subMap.put(name, catalog);
fat[0]--;
totalFiles.put(catalog.getName(), catalog);
System.out.println("创建目录成功!");
showFile();
} else if(value.getAttr() == 3) {
System.out.println("创建目录失败,该目录已存在!");
showFile();
}
} else if(value == null) {
int startNum = setFat(1);
FileModel catalog = new FileModel(name, startNum);
catalog.setFather(nowCatalog); //纪录上一层目录
nowCatalog.subMap.put(name, catalog);
fat[0]--;
totalFiles.put(catalog.getName(), catalog);
System.out.println("创建目录成功!");
showFile();
}
} else {
System.out.println("创建目录失败,磁盘空间不足!");
}
}
/*
*
* 以下为显示该目录下的所有文件信息
*
*/
public void showFile() {
System.out.println("***************** < " + nowCatalog.getName() + " > *****************");
if(!nowCatalog.subMap.isEmpty()) {
for(FileModel value : nowCatalog.subMap.values()) {
if(value.getAttr() == 3) { //目录文件
System.out.println("文件名 : " + value.getName());
System.out.println("操作类型 : " + "文件夹");
System.out.println("起始盘块 : " + value.getStartNum());
System.out.println("大小 : " + value.getSize());
System.out.println("<-------------------------------------->");
}
else if(value.getAttr() == 2) {
System.out.println("文件名 : " + value.getName() + "." + value.getType());
System.out.println("操作类型 : " + "可读可写文件");
System.out.println("起始盘块 : " + value.getStartNum());
System.out.println("大小 : " + value.getSize());
System.out.println("<-------------------------------------->");
}
}
}
for(int i =0; i<2; i++)
System.out.println();
System.out.println("磁盘剩余空间 :" + fat[0] + " " + "退出系统请输入exit");
System.out.println();
}
/*
*
* 以下为删除该目录下某个文件
*
*/
public void deleteFile(String name) {
FileModel value = nowCatalog.subMap.get(name);
if(value == null) {
System.out.println("删除失败,没有该文件或文件夹!");
} else if(!value.subMap.isEmpty()) {
System.out.println("删除失败,该文件夹内含有文件!");
} else {
nowCatalog.subMap.remove(name);
delFat(value.getStartNum());
if(value.getAttr() == 3) {
System.out.println("文件夹 " + value.getName() + " 已成功删除");
showFile();
} else if(value.getAttr() == 2) {
System.out.println("文件 " + value.getName() + "已成功删除");
showFile();
}
}
}
/*
*
* 以下为文件或文件夹重命名方法
*
*/
public void reName(String name, String newName) {
if(nowCatalog.subMap.containsKey(name)) {
if(nowCatalog.subMap.containsKey(newName)) {
System.out.println("重命名失败,同名文件已存在!");
showFile();
} else {
//nowCatalog.subMap.get(name).setName(newName);
FileModel value = nowCatalog.subMap.get(name);
value.setName(newName);
nowCatalog.subMap.remove(name);
nowCatalog.subMap.put(newName, value);
System.out.println("重命名成功!");
System.out.println();
showFile();
}
} else {
System.out.println("重命名失败,没有该文件!");
showFile();
}
}
/*
*
* 以下为修改文件类型
* 修改类型需要打开文件后才能操作
*/
public void changeType(String name, String type) {
nowCatalog = nowCatalog.getFather();
if(nowCatalog.subMap.containsKey(name)) {
FileModel value = nowCatalog.subMap.get(name);
if(value.getAttr() == 2) {
value.setType(type);
nowCatalog.subMap.remove(name);
nowCatalog.subMap.put(name, value);
System.out.println("修改类型成功!");
showFile();
} else if(value.getAttr() == 3) {
System.out.println("修改错误,文件夹无法修改类型!");
openFile(value.getName());
}
} else {
System.out.println("修改错误,请检查输入文件名是否正确!");
}
}
/*
* 以下为打开文件或文件夹方法
*
*/
public void openFile(String name) {
if(nowCatalog.subMap.containsKey(name)) {
FileModel value = nowCatalog.subMap.get(name);
if(value.getAttr() == 2) {
nowCatalog = value;
System.out.println("文件已打开,文件大小为 : " + value.getSize());
} else if(value.getAttr() == 3) {
nowCatalog = value;
System.out.println("文件夹已打开!");
showFile();
}
} else {
System.out.println("打开失败,文件不存在!");
}
}
/*
*
* 以下为向文件追加内容方法
* 追加内容需要打开文件后才能操作
*/
public void reAdd(String name, int addSize) {
if(fat[0] >= addSize) {
nowCatalog = nowCatalog.getFather();
if(nowCatalog.subMap.containsKey(name)) {
FileModel value = nowCatalog.subMap.get(name);
if(value.getAttr() == 2) {
value.setSize(value.getSize() + addSize);
reAddFat(value.getStartNum(), addSize);
System.out.println("追加内容成功!正在重新打开文件...");
openFile(name);
} else{
System.out.println("追加内容失败,请确认文件名是否正确输入。");
}
} else {
System.out.println("追加内容失败,请确认文件名是否正确输入!");
showFile();
}
} else {
System.out.println("追加内容失败,内存空间不足!");
}
}
/*
*
* 以下为返回上一层目录
*
*/
public void backFile() {
if(nowCatalog.getFather() == null) {
System.out.println("该文件没有上级目录!");
} else {
nowCatalog = nowCatalog.getFather();
showFile();
}
}
/*
* 以下根据绝对路径寻找文件
*
*/
public void searchFile(String[] roadName) {
FileModel theCatalog = nowCatalog; //设置断点纪录当前目录
if(totalFiles.containsKey(roadName[roadName.length-1])) { //检查所有文件中有无该文件
nowCatalog = root; //返回根目录
if(nowCatalog.getName().equals(roadName[0])) { //判断输入路径的首目录是否root
System.out.println("yes");
/*for(String temp:roadName)
System.out.println(temp);*/
for(int i=1; i<roadName.length; i++) {
if(nowCatalog.subMap.containsKey(roadName[i])) {
/*System.out.println(nowCatalog.getName());
for(Entry<String, FileModel> s : nowCatalog.subMap.entrySet())
System.out.println("键值对:" + s.getValue().getName());
*/
nowCatalog = nowCatalog.subMap.get(roadName[i]); //一级一级往下查
} else {
System.out.println("找不到该路径下的文件或目录,请检查路径是否正确");
nowCatalog = theCatalog;
showFile();
break;
}
}
if(roadName.length>1){
nowCatalog = nowCatalog.getFather(); //返回文件上一级目录
showFile();
}
} else {
nowCatalog = theCatalog;
System.out.println("请输入正确的绝对路径!");
showFile();
}
} else {
System.out.println("该文件或目录不存在,请输入正确的绝对路径!");
showFile();
}
}
/*
* 以下为打印FAT表内容
*
*/
public void showFAT() {
for(int j=0; j<125; j+=5) {
System.out.println("第几项 | " + j + " " + (j+1) + " " + (j+2) + " "
+ (j+3) + " " + (j+4));
System.out.println("内容 | " + fat[j] + " " + fat[j+1] + " " + fat[j+2]
+ " " + fat[j+3] + " " + fat[j+4]);
System.out.println();
}
int j = 125;
System.out.println("第几项 | " + j + " " + (j+1) + " " + (j+2));
System.out.println("内容 | " + fat[j] + " " + fat[j+1] + " " + fat[j+2]);
System.out.println();
showFile();
}
}
最后使用TestFileSystem这个类实现菜单功能
package com.testsystem;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.service.OSManager;
public class TestFileSystem {
public static void main(String[] args) {
try{
OSManager manager = new OSManager();
meun(manager);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void meun(OSManager manager) {
Scanner s = new Scanner(System.in);
String str = null;
System.out.println("***********" + "欢迎使用文件模拟操作系统" + "***********");
System.out.println();
manager.showFile();
System.out.println("请输入命令(输入help查看命令表):");
while ((str = s.nextLine()) != null) {
if (str.equals("exit")) {
System.out.println("感谢您的使用!");
break;
}
String[] strs = editStr(str);
switch (strs[0]) {
case "createFile":
if (strs.length < 4) {
System.out.println("您所输入的命令有误,请检查");
} else {
manager.createFile(strs[1], strs[2],
Integer.parseInt(strs[3]));
}
break;
case "createCatalog":
if (strs.length < 2) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.createCatolog(strs[1]);
}
break;
case "open":
if (strs.length < 2) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.openFile(strs[1]);
}
break;
case "cd":
if (strs.length < 2) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.openFile(strs[1]);
}
break;
case "cd..":
manager.backFile();
break;
case "delete":
if (strs.length < 2) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.deleteFile(strs[1]);
}
break;
case "rename":
if (strs.length < 3) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.reName(strs[1], strs[2]);
}
break;
case "search": {
if (strs.length < 2) {
System.out.println("您所输入的命令有误,请检查!");
} else {
String[] roadName = strs[1].split("/");
/*for(String temp : strs)
System.out.println(temp);
System.out.println(Arrays.toString(strs));
System.out.println(Arrays.toString(roadName));*/
manager.searchFile(roadName);
}
break;
}
case "showFAT":
manager.showFAT();
break;
case "addContents":
if (strs.length < 3) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.reAdd(strs[1], Integer.parseInt(strs[2]));
}
break;
case "changeType":
if (strs.length < 3) {
System.out.println("您所输入的命令有误,请检查!");
} else {
manager.changeType(strs[1], strs[2]);
}
break;
case "help": {
System.out.println("命令如下(空格不能省略):");
System.out
.println("createFile FileName fileType fileSize");
System.out.println("<创建文件 如:createFile marco txt 5 >");
System.out.println();
System.out
.println("createCatalog FatalogName");
System.out.println("<创建目录 如:createCatalog myFile >");
System.out.println();
System.out
.println("open Name.FileTypt");
System.out.println("<打开文件 如:open marco.txt >");
System.out.println();
System.out.println("cd CatalogName");
System.out.println("<打开目录 如: cd myFile >");
System.out.println();
System.out.println("cd..");
System.out.println("<返回上级目录 如: cd..");
System.out.println();
System.out
.println("delete FileName/CatalogName");
System.out.println("<删除文件或目录(目录必须为空)如:delete marco >");
System.out.println();
System.out
.println("rename FileName/CatalogName NewName");
System.out.println("<重命名文件或目录 如: rename myfile mycomputer >");
System.out.println();
System.out
.println("search FileAbsolutedRoad/CatalogAbsolutedRoad");
System.out.println("<根据绝对路径寻找文件或者目录 如: search root/marco >");
System.out.println();
System.out.println("showFAT");
System.out.println("<查看FAT表 如: showFAT>");
System.out.println();
System.out.println();
System.out.println("下列命令需要打开文件后操作:");
System.out
.println("addContents FileName ContentSize");
System.out.println("<在文件内增加内容 如:ddContents marco 4 >");
System.out.println();
System.out
.println("changeType FileName newType");
System.out.println("<改变文件类型 如: changeType marco doc>");
System.out.println();
break;
}
default:
for(String st : strs)
System.out.println(st);
System.out.println("您所输入的命令有误,请检查!");
}
System.out.println("请输入命令(输入help查看命令表):");
}
}
public static String[] editStr(String str) {
Pattern pattern = Pattern.compile("([a-zA-Z0-9.\\\\/]*) *");// 根据空格分割输入命令
Matcher m = pattern.matcher(str);
ArrayList<String> list = new ArrayList<String>();
while(m.find()){
list.add(m.group(1));
}
String[] strs = list.toArray(new String[list.size()]);
for (int i = 1; i < strs.length; i++) { // 判断除命令以外每一个参数中是否含有 "."
int j = strs[i].indexOf(".");
if (j != -1) { // 若含有"." 将其切割 取前部分作为文件名
String[] index = strs[i].split("\\."); // 使用转义字符"\\."
strs[i] = index[0];
}
}
return strs;
}
}