實驗5 磁盤存儲空間的管理
一、實驗目的
??? 磁盤是用戶存放程序和數據的存儲設備,磁盤管理的主要目的是充分有效地利用磁盤空間。本實驗模擬實現磁盤空間的分配與回收,使學生對磁盤空間的管理有一個較深入的理解。
二、實驗內容
實驗任務:用位示圖管理磁盤空間實現磁盤塊的分配與回收
(1)假定現有一個磁盤組,共有8個柱面。每個柱面有4個磁道,每個磁道又劃分成4個物理盤塊。磁盤的空間使用情況用位示圖表示。位示圖用若干個字構成,每一位對應一個磁盤塊。“1”表示占用,“0”表示空閑。假定字長為16位,一個字可用來模擬磁盤的一個柱面,其位示圖如下圖所示。位示圖的初始狀態為第1個字為“1”,其他全部空閑。
字/位 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | ||||||||||||||||
….. | ||||||||||||||||
7 |
(2)為文件分配磁盤空間。首先輸入文件信息,主要包括文件名、文件大小等信息;然后根據位示圖為文件分配磁盤塊,磁盤塊可以不連續分配。要求輸出分配的磁盤塊的相對塊號和其絕對地址CHS(柱面號、磁頭號、扇區號),輸出位示圖。
(3)釋放文件所占的磁盤空間。輸入文件名,釋放其所占的磁盤空間。要求輸出該文件所分配的磁盤塊的相對塊號和其絕對地址CHS,輸出位示圖。
(4)根據用戶選擇輸出磁盤位示圖和磁盤中的所有文件信息。
三、測試用例
(0)初始磁盤位示圖和文件列表
(1)首先為3個以上的文件分配磁盤空間
設置f1、f2、f3三個文件,文件申請的磁盤空間大小分別為5KB、10KB、20KB。
【1】創建f1文件,文件大小為5KB。
【2】創建f2文件,文件大小為10KB。
【3】創建f3文件,大小為20KB。
(2)刪除先創建的一個文件
刪除f1文件。可以看到扇區16~扇區20已經被設置為0,表示未分配(空閑)扇區。
(3)為新的文件分配磁盤空間,容量大于剛剛刪除掉的那個文件
重新申請f1文件,文件大小為30KB。
(4)隨機刪除各個文件,看看磁盤空間的變化情況
【1】刪除f2文件
【2】刪除f3文件
【3】刪除f1文件
(5)所有的文件都刪除掉時,磁盤恢復為初始化狀態
如第(4)步中【3】刪除f1文件所示。
程序使用完畢后,退出系統。
四、實驗分析與總結
(1)數據結構說明
【1】FCB的數據結構
??? FCB的代碼實現如下圖所示。
在本實驗中,利用struct構造FileInfo結構體,實現對文件基本信息的記錄,即文件控制塊。
該數據結構的基本變量包括:文件名字的字符串file_name、文件大小的整型單變量file_size、文件分配扇區的一維數組allocated_sectors。
【2】磁盤空間的數據結構
磁盤空間的代碼實現如下圖所示。
在本實驗中,利用struct構造StorageManager結構體,實現磁盤空間的初始化和管理。
該數據結構的基本變量包括:可用扇區總數的整型單變量available_sectors、磁盤位示圖的二維數組bitmap、文件映射的哈希表files。
該數據結構的功能包括:構造磁盤空間函數createFile、創建文件(給文件分配磁盤空間)函數createFile、顯示磁盤存儲狀態函數displayStatus、顯示磁盤中的文件序列函數fileDetails、刪除文件(回收給文件分配的磁盤空間)函數deleteFile。
(2)程序流程圖
【1】主函數的程序流程圖
主要代碼段:
對應流程圖:
【2】構造磁盤空間函數的程序流程圖
【3】創建文件(給文件分配磁盤空間)函數的程序流程圖
【4】顯示磁盤存儲狀態函數的程序流程圖
【5】顯示磁盤中的文件序列函數的程序流程圖
【6】刪除文件(回收給文件分配的磁盤空間)函數的程序流程圖
【7】菜單函數的程序流程圖
(3)程序運行結果,打印程序運行時的初值和運行結果
如【三、測試用例】中所示。測試的流程圖如下圖所示。
(4)實驗知識點總結和實驗收獲與體會
1:加深了對磁盤存儲空間管理的理解,將抽象的概念應用到實際情況中。位示圖演示了如何有效地管理資源,特別是在多個文件競爭相同磁盤塊的情況下。實際磁盤操作的各步驟內容如下所示。
步驟 | 具體內容 |
步驟1:初始化位示圖 | 初始化一個位示圖來表示磁盤空間的占用情況。 使用16位字來表示一個柱面的狀態,初始狀態為第一個字為"1",其余全部為"0",表示柱面1被占用,其余柱面為空閑。 |
步驟2:文件分配磁盤空間 | 用戶輸入文件信息,包括文件名和文件大小。 根據位示圖為文件分配磁盤塊,可以不連續分配。這意味著文件的數據塊可以分散在磁盤上。 輸出分配的磁盤塊的相對塊號和其絕對地址CHS(柱面號、磁頭號、扇區號)。 更新位示圖以反映已分配的磁盤塊狀態。 |
步驟3:釋放文件所占的磁盤空間 | 用戶輸入要釋放的文件名。 根據文件名查找該文件所占用的磁盤塊。 輸出被釋放的磁盤塊的相對塊號和其絕對地址CHS。 更新位示圖以反映已釋放的磁盤塊狀態。 |
步驟4:輸出磁盤位示圖和文件信息 | 用戶可以選擇輸出磁盤位示圖,以查看磁盤空間的占用情況。 用戶還可以選擇輸出磁盤中的所有文件信息,包括文件名、大小和存儲位置等信息。 |
2:位示圖法是磁盤空間管理方法的其中一個,用于盤塊的分配、回收,并且涉及絕對地址與邏輯盤塊之間的轉換。磁盤上的所有盤塊都有一個bit與之對應,由所有盤塊所對應的位構成一個集合,稱為位示圖。位示圖主要是由二維數組表示的,其中行號稱為字號,列號稱為位號。位示圖的示例圖如下所示。
3:磁盤塊是存儲介質上連續扇區所組成的一個區域,也被稱作物理塊、簇。磁盤塊的重要性如下:①讀取方便:由于扇區的存儲數量比較小,所以OS將相鄰的扇區組合在一起,形成一
個塊,再對塊進行整體的操作。②分離對底層的依賴:OS忽略對底層物理存儲結構的設計。通過虛擬出來磁盤塊的概念,在系統中認為塊是最小的單位。
4:塊是主存和輔助進行信息交換的最小單位,每次總是交換一塊或整數塊信息。
5:磁盤的物理地址CHS由柱面(Cylinder)、磁頭(Head)、扇區(Sector)構成。磁盤的物理結構如下圖所示。
6:在邏輯盤塊地址LBA與物理地址CHS的轉換中,假設磁頭數是n,每個磁道的扇區數是m,則柱面號、磁頭號、扇區號的計算公式如下所示。
目標計算量 | 計算公式 |
柱面號C | C = LBA / (n * m) |
磁頭號H | H = (LBA / m) % n |
扇區號S | S = (LBA % m) |
7:磁盤管理的其他方法包括:空閑表法(主要用于交換區管理,可采用的分配算法有首次適應算法和最佳適應算法)、空閑鏈法(FAT系統采用,包括空閑盤塊鏈和空閑盤區鏈)、成組鏈接法(Linux系統采用,采用了空閑表和鏈表進行結合)。
(6)實驗源代碼
#include <iostream> #include <vector> #include <unordered_map> using namespace std; // 文件信息結構體(FCB,file control block) struct FileInfo { ? ? ? string file_name; ? ? ? ? ? ? ? // 文件名字 ? ? int file_size; ? ? ? ? ? ? ? ? ?// 文件大小 ? ? vector<int> allocated_sectors; ?// 文件分配的扇區 }; // 存儲管理器結構體(磁盤管理) struct StorageManager { ? ? ? ? ? ? ? ? ? ? ? ? int available_sectors; ? ? ? ? ? ? ? ? ?// 可用扇區總數 ? ? vector<vector<int>> bitmap; ? ? ? ? ? ? // 磁盤位圖 ? ? unordered_map<string, FileInfo> files; ?// 文件映射 ? ? StorageManager(); ? ? ? ? ? ? ? ? ? ? ? // 構造函數 ? ? bool createFile(const string&, int); ? ?// 創建文件 ? ? void displayStatus(); ? ? ? ? ? ? ? ? ? // 顯示存儲狀態 ? ? void fileDetails(const FileInfo&); ? ? ?// 顯示文件詳情 ? ? bool deleteFile(const string&); ? ? ? ? // 刪除文件 }; // 構造函數 // 假定現有一個磁盤組,共有8個柱面。每個柱面有4個磁道,每個磁道又劃分成4個物理盤塊。 StorageManager::StorageManager() : available_sectors(128) { ? ? bitmap.resize(8, vector<int>(16, 0)); ? // 構造8*16個空盤塊 ? ? for (int j = 0; j < 16; ++j) { ? ? ? ? bitmap[0][j] = 1; ?// 預留第一行作為系統文件,該柱面不可用 ? ? ? ? // 位示圖的初始狀態為第1個字為“1”,其他全部空閑。 ? ? } } // 創建文件函數 bool StorageManager::createFile(const string& name, int size) { ? ? if (files.find(name) != files.end()) { ?// 如果文件名字不在末尾,則沖突 ? ? ? ? cout << "錯誤: 文件已存在。"<< endl; ? ? ? ? return false; ? ? } ? ? ? if (size > available_sectors) { ? ? // 如果文件大小大于空閑扇區大小 ? ? ? ? cout << "錯誤: 空間不足。"<< endl; ? ? ? ? return false; ? ? } ? ? ? ? // 創建新文件的FCB ? ? FileInfo newFile{ name, size, {} }; ? ? ? ? // 更新位示圖中信息 ? ? for (int i = 0; i < bitmap.size() && size > 0; ++i) { ? ? ? ? for (int j = 0; j < bitmap[i].size() && size > 0; ++j) { ? ? ? ? ? ? if (bitmap[i][j] == 0) { ? ?// 如果這個盤塊為空 ? ? ? ? ? ? ? ? bitmap[i][j] = 1; ? // 設置為已經分配 ? ? ? ? ? ? ? ? newFile.allocated_sectors.push_back(i * 16 + j); ? ?// 分配區增加這個盤塊 ? ? ? ? ? ? ? ? --size; ? ? // 空閑區大小-=1 ? ? ? ? ? ? ? ? --available_sectors; ? ?// 同上 ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? files[name] = newFile; ?// hash表設置 ? ? fileDetails(newFile); ? // 顯示新建文件詳情 ? ? return true; } // 顯示磁盤分配情況函數 void StorageManager::displayStatus() { ? ? cout << "磁盤位圖:" << endl; ? ? for (int i = 0; i < bitmap.size(); ++i) { ? ? ? ? for (int j = 0; j < bitmap[i].size(); ++j) { ? ? ? ? ? ? cout << bitmap[i][j] << ' '; ? ? ? ? } ? ? ? ? cout << endl; ? // 換行顯示 ? ? } ? ? ? ? cout << endl << "文件列表:" << endl; ? ? for (const auto& pair : files) { ? ? ? ? cout << pair.first << "\t大小: " << pair.second.file_size << endl; ? ? } ? ? cout << endl; } // 顯示文件內存詳情函數 void StorageManager::fileDetails(const FileInfo& file) { ? ? cout << "文件 '" << file.file_name << "' 的詳細信息:"<< endl; ? ? for (int sector : file.allocated_sectors) { ? ? ? ? cout << "扇區: " << sector << ";"; ? ?//遍歷扇區 ? ? } ? ? cout << endl; } // 刪除文件函數 bool StorageManager::deleteFile(const string& name) { ? ? auto it = files.find(name); ? ? if (it == files.end()) { ? ? ? ? cout << "錯誤: 文件不存在。"<< endl; ? ? ? ? return false; ? ? } ? ? for (int sector : it->second.allocated_sectors) { ? ? ? ? int i = sector / 16; ? ? ? ? int j = sector % 16; ? ? ? ? bitmap[i][j] = 0; ? ? ? ? ++available_sectors; ? ? } ? ? files.erase(it); ? ? cout << "文件 '" << name << "' 已刪除。"<< endl; ? ? return true; } // 菜單函數 void menu(StorageManager manager){ ? ? manager.displayStatus(); ? ? cout << "根據數字提示選擇操作: "; ? ? cout << endl << "1:創建文件, 2:刪除文件, 3:退出系統"<< endl; } // 主函數 int main() { ? ? StorageManager manager; ? ? int action; ? ? string filename; ? ? int filesize; ? ? while (true) { ? ? ? ? cout << endl; ? ? ? ? menu(manager); ? ? ? ? cin >> action; ? ? ? ? switch (action) { ? ? ? ? ? ? case 1: ? ? ? ? ? ? ? ? cout << "輸入文件名: "; ? ? ? ? ? ? ? ? cin >> filename; ? ? ? ? ? ? ? ? cout << "輸入文件大小: "; ? ? ? ? ? ? ? ? cin >> filesize; ? ? ? ? ? ? ? ? if (manager.createFile(filename, filesize)) { ? ? ? ? ? ? ? ? ? ? cout << "文件創建成功。\n"; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case 2: ? ? ? ? ? ? ? ? cout << "輸入要刪除的文件名: "; ? ? ? ? ? ? ? ? cin >> filename; ? ? ? ? ? ? ? ? if (manager.deleteFile(filename)) { ? ? ? ? ? ? ? ? ? ? cout << "文件刪除成功。\n"; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case 3: ? ? ? ? ? ? ? ? cout << "程序退出。\n"; ? ? ? ? ? ? ? ? return 0; ? ? ? ? ? ? default: ? ? ? ? ? ? ? ? cout << "無效的操作。\n"; ? ? ? ? } ? ? } ? ? return 0; } /* 測試用例: 【創建文件】 1 f1 5 ? 1 f2 10 1 f3 20 【刪除f1】 2 f1 【重新創建更大的f1】 1 f1 10 【隨機刪除】 2 f2 2 f3 2 f1 【結束】 */ |
五、實驗指導
(1)程序主框架和數據結構
程序主框架可參考內存管理實驗,功能主要包括:分配空間、回收空間、打印位示圖、打印文件信息等。
數據結構主要包括:
位示圖:保存磁盤分配情況;
文件基本信息表:包括文件名、文件長度、創建時間、文件分配的相對磁盤號等。
(2)申請和釋放磁盤塊操作
申請一個磁盤塊時,由磁盤管理程序檢查位示圖,找出一個為0的位,計算磁盤的物理地址,即求出它的柱面號、磁道號和扇區號。
釋放一個相對物理塊時,磁盤管理程序計算該塊在位示圖中的位置,再把相應由“1”改為“0”。由相對塊號計算字號和位號。
(3)磁盤空間分配和回收流程圖