基于Java开发的(控制台)模拟的多用户多级目录的文件系统【100010035】

news2024/11/30 12:42:35

多级文件系统

1 设计目的

为了加深对文件系统内部功能和实现过程的理解,设计一个模拟的多用户多级目录的文件系统,并实现具体的文件物理结构、目录结构以及较为完善的文件操作命令集。

2 设计内容

2.1系统操作

操作命令风格:本文件系统的操作命令风格将采用windows系统的文件操作命令风格,操作命令区分大小写,并能在用户错误地执行某些操作之后给出及时反馈,提供良好的交互体验。

具体的操作:本文件系统将实现以下功能操作:

在这里插入图片描述

2.2文件物理结构

本文件系统的文件物理结构将采用顺序结构,即将文件记录存储在一块连续的磁盘空间中。相应地,磁盘空间的分配也采用连续分配的方式。

2.3文件目录结构

本文件系统的文件目录结构将采用树形目录结构。树形目录结构的优点是可以更方便有效地管理用户的文件,特别是在多用户系统且用户的文件数量较多的情境中。树形目录结构也是目前最为流行的文件目录结构之一,比较符合大多数人的使用习惯。

2.4磁盘空间管理

本文件系统的磁盘空间管理采用位示图来进行管理,用户可以使用show命令来显示磁盘空间位示图以查看当前系统的磁盘空间使用情况。

2.5额外功能

本文件系统提供查看系统操作命令集的功能,用户可以使用help命令来查看本系统已实现的功能,优化用户的使用体验。

另外,本文件系统还提供了将创建的文件保存到电脑本地的功能,以便用户下次使用本系统时能查看自己所创建的文件。2.6编程语言和环境

本文件系统的编程语言采用Java语言,运行环境为JDK 1.8版本及以上。

3 设计步骤

3.1需求分析

3.1.1功能需求

本文件系统的功能模块将细分为三个模块:用户管理模块、文件管理模块、系统管理模块。各个模块的功能需求如表3.1~表3.3所示。

表 3. SEQ 表 \ ARABIC \s 1 1 用户管理模块功能需求*

名称详细描述
用户注册用户使用register命令注册一个系统用户,并要求输入用户名和密码
用户登录用户使用login命令进行登录,需要输入用户名和密码进行身份校验
用户注销用户使用logout命令注销当前已登录的用户

表 3.2 文件管理模块功能需求

名称详细描述
创建目录用户使用mkdir命令创建一个文件目录,文件目录名不能和当前目录下的文件或文件目录重名,并且不区分大小写
列出文件用户使用dir命令列出当前目录下的所有文件的详细信息,支持使用路径名
切换目录用户使用cd命令切换到目标目录,路径名使用windows系统的风格
创建文件用户使用create命令创建一个文件,文件名不能和当前目录下的文件或文件目录重名,并且不区分大小写
打开文件用户使用open命令打开一个文件,支持使用路径名
读取文件用户使用read命令读取一个已打开的文件,可向后读取和向前读取
写入文件用户使用write命令向一个已打开的文件写入记录
关闭文件用户使用close命令关闭一个已打开的文件
删除文件用户使用delete命令删除一个存在的文件或文件目录,支持使用路径名
重命名文件用户使用rename命令对一个文件或文件目录进行重命名,新的名称不能和当前目录下的文件或文件目录重名,并且不区分大小写

表 3.3 系统管理模块功能需求

名称详细描述
显示帮助用户使用help命令查看当前系统支持的操作命令以及使用方法
显示磁盘位示图用户使用show命令查看当前磁盘空间的位示图和其他信息
退出系统用户使用exit命令退出文件系统,系统在退出前会保存用户信息、文件信息和磁盘空间信息

3.1.2性能需求

本文件系统具有较高的响应比,在文件信息不是特别多的时候能够做到0延迟响应。并且本文件系统运行所需的内存空间比较小,保存文件的大小与文件信息的多少成正比。

3.1.3交互需求

用户与本文件系统的交互在控制台中进行,并且可以方便地查看系统操作命令,降低了用户的学习使用成本。

本文件系统具有良好的信息展示功能,包括文件信息展示、文件内容展示、操作命令展示、位示图展示,使用户可以及时地获取自己所需要的信息。

本文件系统具有友好的错误信息反馈。在用户想要执行一项不被允许的操作时(如打开不存在的文件)能够给予用户正确、简洁的引导式的错误反馈。

3.2概要设计

3.2.1设计思想

本文件系统在设计上采用模块化的思想,将服务类型一致的功能划分到同一个模块,使项目整体上比较清晰。并且每个模块都提供对外调用的接口,这样就能让其他模块在需要的时候调用本模块的某些功能,实现复用。

3.2.2模块设计

本文件系统分为用户管理模块、文件管理模块和系统管理模块三个大模块。其中各个模块细分如下:

  • 用户管理模块:负责提供用户注册、用户登录、用户注销三个功能。
  • 文件管理模块:文件管理模块还可分为文件模块、文件目录模块以及磁盘模块三个小模块。其中:
    • 文件模块:负责提供创建文件、打开文件、读取文件、写入文件、关闭文件、删除文件以及重命名文件共七个功能。
    • 文件目录模块:负责提供创建目录、切换目录、列出文件以及解析路径共四个功能。
    • 磁盘模块:负责提供存储记录、释放磁盘空间、读取记录、保存磁盘数据以及加载磁盘数据共五个功能。
    • 系统管理模块:系统管理模块有一个下属模块:打印信息模块,该模块负责提供显示文件列表、显示文件内容、显示帮助列表以及显示位示图共四个功能。

具体的系统模块图如图3.1所示。

在这里插入图片描述

图3.1 系统模块图

3.2.3抽象数据类型定义

系统用户信息实体类定义如下:

public class User implements Serializable {

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;
}

文件控制块实体类定义如下:

public class FileControlBlock implements Serializable {

    /**
     * 是否是目录文件
     */
    private boolean isDirectory;

    /**
     * 文件名(包括了拓展名)
     */
    private String fileName;

    /**
     * 拓展名
     */
    private String suffix;

    /**
     * 起始盘块号
     */
    private Integer startBlock;

    /**
     * 所占用的盘块数
     * 文件大小 = 一个盘块的大小 * 所占用的盘块数
     */
    private Integer blockNum;

    /**
     * 文件属性:保护码列表
     */
    private List<ProtectType> protectTypeList;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 最后一次修改时间
     */
    private LocalDateTime updateTime;
}

树形目录结构实体类定义如下:

public class Directory implements Serializable {

    /**
     * 文件控制块
     */
    private FileControlBlock fileControlBlock;

    /**
     * 在树形目录结构中的位置
     */
    private Integer index;

    /**
     * 文件夹属性:子目录项集合
     */
    private List<Directory> childDirectory;

    /**
     * 父目录项的位置
     */
    private Integer parentIndex;

打开的文件信息实体类定义如下:

public class ActiveFile {

    /**
     * 文件控制块
     */
    private FileControlBlock fileControlBlock;

    /**
     * 文件记录
     */
    private List<Character> fileRecord;

    /**
     * 读指针
     */
    private Integer readPtr;

    /**
     * 写指针
     */
    private Integer writePtr;
}

虚拟磁盘空间实体类定义如下:

public class Disk implements Serializable {

    /**
     * List<Character>: 表示一个盘块
     * List<List<Character>>: 表示所有盘块的集合,即一个磁盘
     */
    private List<List<Character>> disk;
    /**
     * 表示存储在该磁盘上的系统用户集
     */
    private Map<String, User> userMap;
    /**
     * 表示存储在该磁盘上的所有文件控制块
     */
    private List<FileControlBlock> fileControlBlockList;
    /**
     * 表示存储在该磁盘上的树形结构目录,第0个元素为根目录
     */
    private List<Directory> directoryStruct;
    /**
     * 表示存储在该磁盘上的磁盘位示图
     */
    private Integer[][] bitmap;
}

3.2.4主程序的流程图

主程序的流程图如图3.2所示。

在这里插入图片描述

图3.2 主程序流程图

3.3详细设计

3.3.1系统算法IPO表

表3.4~表3.26展示了本文件系统的各个功能的具体实现算法IPO表,介绍了各功能模块的编号、模块、日期、作者、被调用模块、输入输出、数据处理与相关数据。如下所示:

表3.4用户注册IPO表

在这里插入图片描述

表3.5用户登录IPO表

在这里插入图片描述

表3.6用户注销IPO表

在这里插入图片描述

表3.7创建文件IPO表

在这里插入图片描述

表3.8打开文件IPO表

在这里插入图片描述

表3.9读取文件IPO表

在这里插入图片描述

表3.10写入文件IPO表

在这里插入图片描述

表3.11关闭文件IPO表

在这里插入图片描述

表3.12删除文件IPO表

在这里插入图片描述

表3.13重命名文件IPO表

在这里插入图片描述

表3.14创建目录IPO表

在这里插入图片描述

表3.15切换目录IPO表

在这里插入图片描述

表3.16列出文件IPO表

在这里插入图片描述

表3.17解析路径IPO表

在这里插入图片描述

表3.18存储记录IPO表

在这里插入图片描述

表3.19释放磁盘空间IPO表

在这里插入图片描述

表3.20读取记录IPO表

在这里插入图片描述

表3.21保存磁盘数据IPO表

在这里插入图片描述

表3.22加载磁盘数据IPO表

在这里插入图片描述

表3.23显示文件列表IPO表

在这里插入图片描述

表3.24显示文件内容IPO表

在这里插入图片描述

表3.25显示帮助列表IPO表

在这里插入图片描述

表3.26显示位示图IPO表

在这里插入图片描述

3.4调试分析

一开始在实现树形结构目录的时候,我的文件目录项实体类是这样的:

public class Directory implements Serializable {

    /**
     * 文件控制块
     */
    private FileControlBlock fileControlBlock;

    /**
     * 文件夹属性:子目录项集合
     */
    private List<Directory> childDirectory;

    /**
     * 父目录项
     */
    private Directory parentDirectory;
}

在一个目录项之中,持有其父目录项的引用,如果该目录项是目录文件的话,还持有归属于它的子目录项的集合,这样便可以实现一个树形结构的目录。而在磁盘中只要持有一个对根目录的引用就可以查找到所有的目录项,这样是很方便的一种实现方案。

但是,这样的实体类在程序实际运行起来的时候是有问题的。假设有这样的情形:directoryA是一个表示目录文件的目录项,directoryB是一个表示数据文件的目录项,并且directoryB的父目录项是directoryA。这样的关系,在程序中表现为,directoryA的childDirectory属性中持有对directoryB的引用,而directoryB的parentDirectory属性持有对directoryA的引用,这样就造成了循环引用。

这样的循环引用问题,在Java的序列化和反序列化的时候表现的尤为明显。因为本文件系统可以将系统运行过程中的磁盘数据保存到本地文件中,也可以将本地文件中的磁盘数据加载到程序中,前者是通过序列化实现的,后者是通过反序列化实现的。但是由于循环引用的问题,在进行序列化和反序列化的时候,会报栈溢出的错误,导致磁盘数据加载不了(表现为找不到本该存在的目录项)。

当时发现这个问题的时候,我通过IDEA的debug功能一步一步地调试,最终定位到问题的根源以及想出了解决方案。改进后的文件目录项实体类如下所示:

public class Directory implements Serializable {

    /**
     * 文件控制块
     */
    private FileControlBlock fileControlBlock;

    /**
     * 在树形目录结构中的位置
     */
    private Integer index;

    /**
     * 文件夹属性:子目录项集合
     */
    private List<Directory> childDirectory;

    /**
     * 父目录项的位置
     */
    private Integer parentIndex;
}

这样进行了修改之后,在磁盘中要保存的是整个树形目录结构的所有目录项的列表,如下所示:

public class Disk implements Serializable {

    ...

    /**
     * 表示存储在该磁盘上的树形结构目录,第0个元素为根目录
     */
    private List<Directory> directoryStruct;

    ...
}

3.5系统测试

3.5.1 help命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
help显示本系统的帮助列表help命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.2 exit命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
exit退出本系统exit命令功能正常

实际测试结果如下图所示:
在这里插入图片描述

3.5.3 register命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
register注册用户失败:用户名不能为空缺少[用户名]参数
register pw注册用户失败:密码不能为空缺少[密码]参数
[pw]这个用户没有被注册register pw 123注册用户成功register命令功能正常
[pw]这个用户已被注册register pw 123注册用户失败:该用户已存在[pw]是一个已存在的用户,不能重复注册

实际测试结果如下图所示:
在这里插入图片描述

3.5.4 login命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
login用户登录失败:该用户不存在缺少[用户名]参数,系统会判定[用户名]为空字符
login pw用户登录失败:密码错误缺少 [密码]参数,系统会判定[密码]为空字符
[pw]这个用户已被注册,且密码不是456login pw 456用户登录失败:密码错误[pw]这个用户的密码不正确
[unknown]这个用户没有被注册login unknown 123用户登录失败:该用户不存在[unknown]这个用户不存在(没有注册过)
[pw]这个用户已被注册,且密码是123login pw 123登录成功用户名和密码都正确,登录成功

实际测试结果如下图所示:

在这里插入图片描述

3.5.5 logout命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
已登录了某个用户logout注销成功logout命令功能正常
当前没有登录用户logout用户注销失败:当前没有登录用户logout命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.6 show命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
show显示位示图信息show命令功能正常

实际测试结果如下图所示:
在这里插入图片描述

注意:以下命令能够正确执行前提都是要在已进行了登录的情况下,如果没有进行登录,系统会给出错误提示信息。所以下述命令的测试都是在已登录了的情况下进行的测试,此前提条件不再赘述,忘悉知。

3.5.7 mkdir命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
mkdir创建目录失败:文件名不能为空缺少[目录名]这个参数,系统会判定目录名为空字符
当前目录下不存在[os]这个子目录mkdir os创建成功,使用[dir]命令可以查看到[os]这个目录的信息mkdir命令功能正常
当前目录下存在[os]这个子目录mkdir os创建目录失败:文件名重复同一个目录中的文件不能重名

实际测试结果如下图所示:
在这里插入图片描述

3.5.8 dir命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
dir列出当前目录下面所有文件的信息dir命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.9 cd命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
cd仍在当前目录如果缺少[目录路径]参数,则停留在当前目录下
当前目录下存在[os]这个子目录cd os进入到os目录cd命令功能正常
当前目录下不存在[os]这个子目录cd os切换目录失败:找不到对应目录cd命令功能正常
存在上一级目录cd …返回到上一级目录cd命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.10 create命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
create创建文件失败:文件名不能为空缺少[文件名]这个参数,系统会判定文件名为空字符
当前目录下不存在[a.txt]这个文件create a.txt创建文件成功,使用[dir]命令可以查看到[a.txt]的信息create命令功能正常
当前目录下存在[a.txt]这个文件create a.txt创建文件失败:文件名重复同一个目录中的文件不能重名
当前目录下存在[a.txt]这个文件create A.txt创建文件失败:文件名重复本系统的文件名不区分大小写

实际测试结果如下图所示:
在这里插入图片描述

3.5.11 open命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
open打开文件失败:文件名不能为空缺少[文件名]这个参数,系统会判定文件名为空字符
当前目录下不存在[b.jpg]这个文件open b.jpg打开文件失败:文件不存在open命令功能正常
当前目录下存在[a.txt]这个文件open a.txt打开文件成功,显示出文件中的内容open命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.12 close命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
当前存在已打开的文件close关闭成功close命令功能正常
当前不存在已打开的文件close关闭文件失败:当前没有文件被打开close命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.13 write命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
当前不存在已打开的文件write,然后输入文件内容,以“###”结尾写入文件失败:请先打开文件再进行写入write命令功能正常
当前存在已打开的文件write,然后输入文件内容,以“###”结尾写入成功,控制台会回显文件的所有内容(包括刚刚写入的内容)write命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.14 read命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
当前存在已打开的文件read显示空字符缺少[要读取的记录个数]参数,系统会判定要读取的记录个数为0
当前存在已打开的文件,且(当前读指针 + 5)< 文件长度read 5显示读取出来的5个字符read命令功能正常
当前存在已打开的文件,且(当前读指针 - 4)>= 0read -4显示读取出来的4个字符read命令支持向后读取

实际测试结果如下图所示:

在这里插入图片描述

3.5.15 delete命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
delete删除文件失败:文件名不能为空缺少[文件名]参数,系统会判定文件名为空字符
当前目录下不存在[b.jpg]这个文件delete b.jpg删除文件失败:找不到对应文件delete命令功能正常
当前目录下存在[a.txt]这个文件delete a.txt删除成功,使用[dir]命令查看a.txt文件不存在delete命令功能正常

实际测试结果如下图所示:

在这里插入图片描述

3.5.16 rename命令测试

测试数据如下表:

前提条件命令输入执行结果结果分析
rename重命名文件失败:文件名不能为空缺少[文件名]参数,系统会判定文件名为空字符
rename b.jpg重命名文件失败:文件名不能为空缺少[新文件名]参数,系统会判定新文件名为空字符
当前目录下不存在[b.jpg]这个文件rename b.jpg c.mp3重命名文件失败:文件不存在rename命令功能正常
当前目录下存在[a.txt]这个文件rename a.txt c.mp3重命名成功,使用[dir]命令可查看a.txt已变为c.mp3rename功能正常

实际测试结果如下图所示:
在这里插入图片描述

3.6使用说明

3.6.1操作命令说明

在这里插入图片描述

本文件系统支持的所有操作命令已在“帮助列表”中列出。想要查看“帮助列表”时只要键入 help 命令即可,如下所示:

现在对本文件系统中的几种操作命令格式做说明:

①无参数命令:例如help、show、exit、dir等都是无参数命令。在使用无参数命令时,只需要键入对应的命令即可,不需要输入额外的参数。如果输入的额外的参数,系统会默认把它丢弃掉,也并不影响使用。

②单参数命令:例如mkdir、create、open等都是单参数命令。使用单参数命令时,输入对应的命令之后,要输入一个(或者至少一个)空格,然后输入正确的参数,最后回车即可。在上述“帮助列表”中的“用法”中,方括号框中表示的是要输入的参数。例如mkdir [目录名],该命令正确的用法是“mkdir test”,表示创建一个名为“test”的新目录。

③多参数命令:例如register、login等都是要输入一个以上参数的命令。在使用多参数命令时,参数和参数之间要使用一个空格进行分隔开。另外,参数的个数要对应。例如在使用login [用户名] [密码],如果输入“login 123”,系统会把“123”当成用户名来识别,而该命令缺少了密码这个参数,系统给出错误提示。

另外,对本文件系统采用的文件路径格式做如下说明:

①目录名与目录名(或文件名)之前用路径分隔符“/”分隔开。例如“cd test/word”表示进入到当前目录下的test文件夹下的word文件夹中。

②全部采用相对路径

③“…”表示上一级目录。例如“cd …”表示回退到上一级目录。

3.6.2磁盘数据保存说明

本文件系统在启动的时候会加载“固定路径”下的“磁盘文件”中的磁盘数据,在正常退出的时候会保存磁盘数据到“固定路径”下的“磁盘文件”中。

“固定路径”是指程序运行文件所在目录中的save文件夹。“磁盘文件”是指save文件夹中的一个名为disk.ser的文件,本文件系统的所有磁盘数据都会保存进里面。如果本文件系统启动的时候找不到disk.ser文件(或save文件夹),系统会初始化磁盘,相当于一个新激活的系统。

本文件系统在正常退出(使用exit命令退出)的之前,会保存当前的磁盘数据到save文件夹中的disk.ser文件中。如果disk.ser文件不存在,会新建一个disk.ser文件;如果disk.ser文件存在,则会进行覆盖写入操作。

3 经验与体会

我的经验和体会是:

①在编程实现多级文件系统之前,要先确定好文件的逻辑结构、文件的物理结构、文件控制块信息、树形目录结构的表现形式、磁盘空间的表示显示、文件记录在磁盘中的表现形式、磁盘空间的分配方式、磁盘空间的管理形式等重要问题。只有思考了以上问题以及确定好具体的实现方案之后,才能着手与正式的编程实现,否则就在编程的同时遇到很多具有极强关联性的问题,导致了编程后期可能要对系统进行重构。

②在设计本文件系统的交互的时候,要考虑到用户的使用感受,应该使用户能以尽量简单的形式使用本系统,操作命令的输入不要过于冗余而繁杂。在这个方面可以参考很多优秀的操作系统的实现方式,比如Linux和Windows系统。

4 重要数据结构或疑难部分说明

4.1重要数据结构

大部分重要数据结构已经在之前的设计步骤中的需求分析的抽象数据类型定义小节中进行了说明,这里便不再赘述。关于树形结构目录的实现则在实体类Directory中。

4.2疑难部分说明

除了树形目录结构的具体实现比较难之外(该实现已在调试分析中进行说明),另一个疑难部分就是在存储文件记录时为文件记录分配磁盘空间和修改位示图的具体实现。存储文件记录的具体实现为:

public CommonResult<FileControlBlock> storeRecord(FileControlBlock fileControlBlock, List<Character> record) {
    if (CollectionUtil.isEmpty(record)) {
        return CommonResult.operateSuccess(null);
    }

    // 修改位示图,为重新分配盘块做准备
    changeBitmapStatus(fileControlBlock.getStartBlock(), fileControlBlock.getBlockNum(), true);
    // 计算存储该长度记录所需要的盘块数量
    Integer requiredNum = Math.ceilDivide(record.size(), DiskConstant.BLOCK_SIZE);

    int count = 0;
    int startBlockId = DiskConstant.RECORD_START_BLOCK;

    for (int i = 0; i < DiskConstant.BITMAP_ROW_LENGTH; i++) {
        for (int j = 0; j < DiskConstant.BITMAP_LINE_LENGTH; j++) {
            // 如果该盘块空闲
            if (DiskConstant.BITMAP_FREE.compareTo(Memory.getInstance().getBitmap()[i][j]) == 0) {
                if (count == 0) {
                    // 记下起始盘块号: 当前行 * 总列数 + 当前列
                    startBlockId = i * DiskConstant.BITMAP_LINE_LENGTH + j;
                }

                count++;
                if (count == requiredNum) {
                    // 如果有足够的连续盘区供存储,则进行存储,并改变位示图的相应状态
                    storeToDisk(startBlockId, record);
                    changeBitmapStatus(startBlockId, requiredNum, false);
                    return CommonResult.operateSuccess(fileControlBlock.setStartBlock(startBlockId).setBlockNum(requiredNum));
                }
            } else {
                // 因为是连续分配,如果该盘块不空闲则要重新计数
                count = 0;
            }
        }
    }

    return CommonResult.operateFailWithMessage("[分配盘块失败]: 磁盘空间不足");
}

在该方法中调用了两个关键的方法:storeToDisk(startBlockId, record)和changeBitmapStatus(startBlockId, requiredNum, false)。

其中的storeToDisk(startBlockId, record)方法的作用是将文件记录存储在磁盘中。传入参数startBlockId表示起始盘块号,传入参数record表示待存储的文件记录。其具体实现为:

private void storeToDisk(Integer startBlockId, List<Character> record) {
    int index = 0;
    int blockId = startBlockId;
    Disk disk = DataCache.getInstance().getDisk();

    // 可以直接覆盖掉原来的磁盘中的记录
    for (Character ch : record) {
        if (index >= DiskConstant.BLOCK_SIZE) {
            // 如果一个盘块的空间被用完了,则使用下一个盘块来进行存储
            blockId++;
            index = 0;
        }

        disk.getDisk().get(blockId).add(index, ch);
        index++;
    }

    while (index < DiskConstant.BLOCK_SIZE && disk.getDisk().get(blockId).size() > index) {
        // 擦除最后一个盘块中没有用到的空间
        disk.getDisk().get(blockId).set(index, null);
        index++;
    }
}

其中的changeBitmapStatus(startBlockId, requiredNum, false)方法的作用是更改相应的位示图的状态(仅适用于连续分配的方式)。传入参数startBlockId表示起始盘块号,传入参数blockNum表示要更改的盘块数量,传入参数changeToFree表示要更改的状态(true-表示空闲状态,false-表示已分配状态)。其具体实现为:

private void changeBitmapStatus(Integer startBlockId, Integer blockNum, boolean changeToFree) {
    if (Objects.isNull(startBlockId) || startBlockId < DiskConstant.RECORD_START_BLOCK ||
        startBlockId >= DiskConstant.BLOCK_NUM || blockNum <= 0) {
        return;
    }

    // 解析该盘块在位示图中的第几行
    int row = startBlockId / DiskConstant.BITMAP_LINE_LENGTH;
    // 解析该盘块在位示图中的第几列
    int line = startBlockId % DiskConstant.BITMAP_LINE_LENGTH;
    for (int i = 0; i < blockNum; i++) {
        Memory.getInstance().getBitmap()[row][line] = changeToFree ? DiskConstant.BITMAP_FREE : DiskConstant.BITMAP_BUSY;
        if (line >= DiskConstant.BITMAP_LINE_LENGTH - 1) {
            line = 0;
            row++;
        } else {
            line++;
        }
    }
}

♻️ 资源

在这里插入图片描述

大小: 2.61MB
➡️ 资源下载:https://download.csdn.net/download/s1t16/87248377

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/84805.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

110115-07-6,Ac-LLM-CHOCalpain 抑制剂

Ac-LLM-CHO (ALLM) is a potent competitive inhibitor of cathepsin L (Ki0.6 nM) and cathepsin B (Ki100 nM). Ac-LLM-CHO (ALLM)是组织蛋白酶L (Ki0.6 nM)和组织蛋白酶B (Ki100 nM)的有效竞争性抑制剂。 编号: 124055中文名称: Calpain 抑制剂 II&#xff1a; Ac-Leu-Leu-M…

[附源码]Node.js计算机毕业设计点餐系统设计Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

游戏开发59课 性能优化

7. 耗电优化 游戏耗电和游戏卡并无必然联系&#xff0c;有些游戏在某些设备上虽然运行很流畅&#xff0c;但发现耗电很厉害&#xff0c;玩了不到半个小时&#xff0c;电量已经出现警报。游戏耗电的原因主要是因为&#xff1a;CPU占用普遍高&#xff0c;内存操作频繁&#xff0…

Spring MVC学习 | 获取请求参数

文章目录一、ServletAPI获取二、控制器方法形参获取2.1 不使用RequestParam注解2.2 使用RequestParam注解2.2.1 简介&使用2.2.2 相关注解2.3 实体类类型的形参三、中文乱码问题3.1 在tomcat中设置编码&#xff08;了解&#xff09;3.2 使用Spring MVC内部过滤器设置编码学习…

【PortSwiggerのWeb Security Academy靶场】SQL Injection系列 9th

Subject Lab: Blind SQL injection with conditional responses Url: portswigger.net/web-securit… Mind Palace 在带着 cookies的后续访问网页时会找到出现的 Welcome back! 标志 > 无法回显 > 采用盲注的方式 0x01 确认注入点 0x02 爆破数据库名 # 测试informati…

qiankun 部署微前端-vue2(一)

自从前后端分离以来&#xff0c;一直都有个困惑&#xff0c;就是随着项目的功能的不断拓展&#xff0c;项目变得不断臃肿&#xff0c;每次打包编译&#xff0c;都要把整个项目编译&#xff0c;非常耗时。如果前端也能像后端一样&#xff0c;在项目搭建初期&#xff0c;有类似微…

C++11【包装器】

包装器&#x1f4d6;1. 为什么需要包装器&#x1f4d6;2. 如何使用包装器&#x1f4d6;3. bind函数&#x1f4d6;1. 为什么需要包装器 包装器也叫做适配器&#xff0c;C中的function本质是一个类模板&#xff0c;也是一个包装器. 为什么需要function呢&#xff1f; 我们来看…

ant-design-vue修改input组件样式

问题场景 不得不说ant-design-vue的样式是真的难改。。。今天尝试了很多种方案&#xff0c;都无疾而终。最终&#xff0c;通过全局scss文件引入的方式解决了。 几种方案&#xff1a; 直接行内样式&#xff0c;发现部分可以&#xff0c;部分不行将style 的scoped属性去掉&#…

非线性负载的主要分类及其特性

非线性负载的主要分类 通常而言&#xff0c;由线性元件原件组成的负载称为线性负载&#xff0c;线性负载的输出与输入呈线性关系&#xff0c;典型的线性负载如电阻、电容和电感等&#xff1b;而由非线性元件构成的负载为非线性负载&#xff0c;在正弦波电压供电时会产生非正弦…

Sentinel服务流控

Sentinel通过流量控制&#xff08;flow control&#xff09;以及熔断降级来保护系统资源 QPS超过阈值直接失败 流量控制&#xff08;flow control&#xff09;&#xff0c;其原理是监控应用流量的 QPS 或并发线程数等指标&#xff0c;当达到指定的阈值时对流量进行控制&#x…

如何使用ABAQUS对新能源动力电池进行Pack分析

电池Pack的仿真&#xff0c;按照系统层次&#xff0c;可从电芯、模组、Pack和整车逐级分析。电芯主要集中于机械性能的材料拟合、激光焊接以及电-化学-热-机耦合建模&#xff0c;模组主要集中于跌落、振动以及模组冷却&#xff0c;Pack主要集中于**、冲击和振动以及Pack热管理&…

Token Merging: Your ViT But Faster

论文&#xff1a;https://arxiv.org/pdf/2210.09461.pdf 代码&#xff1a; https://github.com/facebookresearch/ToMe 这篇论文写的很棒呀&#xff0c;以摘要为例&#xff0c;第一句话指明ToMe的作用&#xff08;提高ViT-based模型的训练和推理速度&#xff09;和特色&#x…

java面试强基(21)

什么是线程和进程? 何为进程? ​ 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程。 ​ 在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一个 J…

提质增效!北京筑龙助力蒙牛集团采招数智化升级

近两年&#xff0c;全球经济下行压力加剧&#xff0c;市场形势波动使得集团企业面临着很大的经营压力。随着数字经济时代的到来&#xff0c;利用数字技术重构价值链、重组业务流程&#xff0c;或创建新的生态系统平台成为集团企业数字化转型的契机。 蒙牛电子采购招标平台作为…

WEB网页设计期末作业个人主页——基于HTML+CSS制作个人简介网站

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

现实中的项目范围变更

大多数招投标或签合同的项目(TOG或TOB),范围变更是极少的,一旦发起范围变更申请,这个流程是非常复杂的,而且会有负面影响,尤其是TOG的项目。 项目范围变更,往往会引起项目金额变更,核减、增加、不变都有可能。 TOG项目的范围变更,常是因为政策变了、上级要求等不可…

(附源码)Springboot网上购物平台 毕业设计 141422

Springboot网上购物平台的开发 摘 要 随着Internet的使用越来越广泛&#xff0c;在传统的商业模式中&#xff0c;对于日常各类商品&#xff0c;人们习惯于到各种商家店铺购买。然而在快节奏的新时代中&#xff0c;人们不一定能为购买各类商品腾出时间&#xff0c;更不会耐心挑…

Docker管理工具Portainer忘记admin登录密码怎么办?

Portainer官网解决方法链接 https://docs.portainer.io/v/ce-2.11/advanced/reset-admin 炒鸡详细步骤&#xff01; 1.查看所有容器,包括未运行的 docker ps -a 2.找到Portainer对应信息 3.停止Portainer容器 docker stop portainerid 我这里就应该是 docker stop 507566…

Unity VFX图表初级到中级教程

Unity VFX图表初级到中级教程 从 Unity 学习新的视觉效果工具并开始制作一些很棒的魔法效果 课程英文名&#xff1a;Unity VFX Graph - Beginner To Intermediate 此视频教程共4.5小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 下载地址 …

【脚本项目源码】Python制作提升成功率90%的表白神器

前言 明天就是拥抱情人节&#xff0c;情侣们会在公开的场合拥抱&#xff0c;向世人宣告你俩的爱意&#xff0c;也让这个寒冷的冬天变得格外温馨。到了年底依然能热情拥抱&#xff0c;也见证了两人情意如昔。 今天小鱼就给大家带来就是的利用Python制作表白神器&#xff0c;记…