作業系統課程設計 —— 模擬磁碟檔案系統實現 (Java)
阿新 • • 發佈:2019-02-12
這是我前段時間做了一個作業系統課程設計作業,使用java實現了命令列輸入對虛擬檔案進行管理。
下面是課程設計要求:
題目五 模擬磁碟檔案系統實現
一、課程設計目的
瞭解磁碟檔案系統的結構、功能和實現。並可練習合作完成系統的團隊精神和提高
程式設計能力。
二、小組人數 建議 3~5 人一組共同完成模擬磁碟檔案系統的實現。 選擇題目“模擬磁碟檔案系統實現”的小組在最終提交時須公開演示及講解。 由於這個題目較複雜,難度和工作量遠大於前面幾個題目,故小組成員最後得分 也酌情高於選擇前面四個題目的同學的分數(高 5~10 分)。 三、程式語言
建議使用一些 Windows 環境下的程式設計語言如 VC、Java,以藉助這些語言的多
執行緒來模擬並行發生的行為。要求圖形介面。
四、課程設計內容
設計一個簡單的檔案系統,用檔案模擬磁碟,用陣列模擬緩衝區,要求:
(1) 支援多級目錄結構,支援檔案的絕對讀路徑;
(2) 檔案的邏輯結構採用流式結構,物理結構採用連結結構中的顯式連結方式;
(3) 採用檔案分配表 FAT;
(4) 實現的命令包括建立目錄、列目錄、刪除空目錄、建立檔案、刪除檔案、顯示
檔案內容、開啟檔案、讀檔案、寫檔案、關閉檔案、改變檔案屬性。可以採用
命令列介面執行這些命令,也可以採用“右擊快捷選單選擇”方式執行命令。
(5) 後編寫主函式對所作工作進行測試。
下面是我實現的功能:
以下為原始碼
首先是一個FileModel類用來記錄檔案或目錄的相關屬性
接著使用OSManager這個類實現對檔案的各種操作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;
}
}