当前位置: 首页 > news >正文

【操作系统】磁盘存储空间的管理

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

相关文章:

  • List集合之UML、特点、遍历方式、迭代器原理、泛型、装拆箱及ArrayList、LinkedList和Vector的区别
  • 在Linux操作系统的ECS实例上安装Hive
  • mysql 输出所在月份的最后一天
  • xrpc: 一个基于消息队列的的Go语言RPC框架
  • 第九届大数据与计算国际会议 (ICBDC 2024) 即将召开!
  • HTTP 与 HTTPS-HTTP 解决了 HTTP 哪些问题?
  • 基于SVM的功率分类,基于支持向量机SVM的功率分类识别,Libsvm工具箱详解
  • 在 Windows 上使用 VC++ 编译 OpenSSL 源码的步骤
  • MySQL多实例部署:从概念到实操的全面指南
  • 手机上wmv怎么转换成视频mp4?3种视频转换方法分享
  • k8s的pod调度之节点选择器
  • spark超大数据批量写入redis
  • 外包干了3个月,技术退步明显
  • 【新手易错点】golang中byte和rune
  • linux安装flink(单节点)
  • [deviceone开发]-do_Webview的基本示例
  • CSS相对定位
  • ES2017异步函数现已正式可用
  • IOS评论框不贴底(ios12新bug)
  • Java面向对象及其三大特征
  • jquery cookie
  • php面试题 汇集2
  • PHP那些事儿
  • vue 个人积累(使用工具,组件)
  • Vultr 教程目录
  • 创建一个Struts2项目maven 方式
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 学习HTTP相关知识笔记
  • 正则与JS中的正则
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • $L^p$ 调和函数恒为零
  • (floyd+补集) poj 3275
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (转)Sql Server 保留几位小数的两种做法
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET CORE Aws S3 使用
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .NET DataGridView数据绑定说明
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net 流——流的类型体系简单介绍
  • .net2005怎么读string形的xml,不是xml文件。
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [BZOJ4337][BJOI2015]树的同构(树的最小表示法)
  • [C++]打开新世界的大门之C++入门
  • [CISCN2019 华东南赛区]Web4
  • [iHooya]2023年1月30日作业解析
  • [java进阶]——方法引用改写Lambda表达式
  • [Java开发之路](14)反射机制