实验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)磁盘空间分配和回收流程图