草庐IT

自己动手从零写桌面操作系统GrapeOS系列教程——22.文件系统与FAT16

成宇佳的技术博客 2023-03-28 原文

学习操作系统原理最好的方法是自己写一个简单的操作系统。


新买的硬盘和优盘在第一次使用时需要格式化,有时候还需要分区。这是为什么呢?分区和格式化到底是干啥呢?本讲将为大家解开这些疑惑。

一、文件系统

1.分区

首先说一下分区,我们平时看到的C盘、D盘等就是一个个分区。硬盘第一个扇区的一部分固定空间叫做分区表,划分分区就是在这个分区表中记录一下各分区的信息,包括各个分区从哪个扇区开始,到哪个扇区结束等。由于GrapeOS所用虚拟硬盘的空间大小只有4MB,没必要分区,所以我们在MBR中也没有填写分区表。

2.格式化

格式化是在某个分区上做的。如果一个盘没有做分区,那就将整个盘作为一个分区看待,GrapeOS就是这样的。大家如果对硬盘或优盘做过格式化就会知道,格式化的时候会让你选择一种文件系统,常见的选项有NTFS、FAT32、exFAT等。所谓格式化就是将某种文件系统的信息写入到这个分区的一部分扇区上。那什么是文件系统呢?下面来简单介绍一下。

3.文件系统

计算机一开始是没有文件和文件系统概念的。前面我们学习了对硬盘的读写,我们知道对硬盘的读写是按扇区为单位进行的。在读写硬盘的时候我们有用到文件的概念吗?没有。到目前为止,我们用的虚拟硬盘上并没有任何文件系统,就和刚买的新硬盘一样,但并不影响我们读写硬盘。但是在没有文件系统的情况下实际使用会非常麻烦。比如你将多个文件写入到硬盘上,你需要记录每个文件存放在了那些扇区上;如果为一个文件增加了一些内容,需要多占用一些扇区,你需要知道哪些扇区是空闲的。这些问题都是需要文件系统处理的。早期的计算机之所以没有文件系统也能用是因为当时的每个外部存储器上的数据都是为某一件事专用的,有配套的程序做处理,并不能像现在随意往硬盘里存放各种文件。总之,文件系统是为了方便在硬盘或其它存储设备上存储数据而抽象出来的一种数据管理方式。只说是抽象出来的,这个不好理解,文件系统有很多种,需要结合一种具体的文件系统讲解才能明白。下面我们介绍一下GrapeOS中用的文件系统FAT16。

二、FAT16

1.FAT16空间分布

首先大家需要明白两个概念,文件属性和文件内容。文件属性一般包含文件名称、大小、修改日期等信息。文件内容是指文件内具体包含的东西,比如一个文本文件,它的内容就是里面的文本信息。
在FAT16文件系统中,一般会将硬盘或某个分区划分为5个部分:引导扇区、FAT1表、FAT2表、根目录区、数据区。如下图所示:

  • 引导扇区就是硬盘或分区的第一个扇区。
  • 根目录区存放的就是根目录中文件和文件夹的属性信息。
  • 数据区存放的是所有文件和文件夹的内容。
  • FAT1表和FAT2表存放的是文件内容的簇号,也就是记录每个文件的内容存放在了哪些扇区中。簇是FAT16数据区中的一个空间单位,每个簇等于若干个扇区,具体等于多少个扇区,需要在引导扇区中设置。在GrapeOS中每个簇设置等于一个扇区。簇是FAT16中用来存放文件数据的基本单位,不可分割,一个簇内的空间不能一部分属于一个文件,而另一部分属于另一个文件。比较特殊的一点是数据区中的簇号不是从0开始的,而是从2开始的。
    FAT2表是FAT1表的备份,大小完全相同,正常情况下里面的数据也完全相同。如果发生不正常的情况可以用FAT2表中的数据恢复FAT1表。在GrapeOS中我们不考虑这种不正常的情况,所以舍弃了FAT2表。如下图所示:

2.FAT16引导扇区

FAT16文件系统引导扇区结构表:

名称 偏移 长度 内容 GrapeOS的值
BS_jmpBoot 0 3 一个短跳转指令 jmp boot_start nop
BS_OEMName 3 8 厂商名称 GrapeOS
BPB_BytsPerSec 11 2 每扇区字节数 0x0200
BPB_SecPerClus 13 1 每簇扇区数 0x01
BPB_RsvdSecCnt 14 2 保留扇区数(引导扇区的扇区数) 0x0001
BPB_NumFATs 16 1 FAT表的份数 0x01
BPB_RootEntCnt 17 2 根目录可容纳的目录项数 0x0200
BPB_TotSec16 19 2 扇区总数 0x2000(4MB)
BPB_Media 21 1 介质描述符 0xf8
BPB_FATSz16 22 2 每个FAT表扇区数 0x0020
BPB_SecPerTrk 24 2 每磁道扇区数 0x0020
BPB_NumHeads 26 2 磁头数 0x0040
BPB_HiddSec 28 4 隐藏扇区数 0x00000000
BPB_TotSec32 32 4 如果BPB_TotSec16是0,由这个值记录扇区数。 0x00000000
BS_DrvNum 36 1 int 13h的驱动器号 0x80
BS_Reservedl 37 1 未使用 0x00
BS_BootSig 38 1 扩展引导标记 0x29
BS_VolID 39 4 卷序列号 0x00000000
BS_VolLab 43 11 卷标 Grape OS
BS_FileSysType 54 8 文件系统类型 FAT16
引导代码及其它 62 448 引导代码、数据及其它填充字符等
结束标志 510 2 0xAA55 0xAA55

从上表中可以看到,FAT16引导扇区中前62个字节是有固定格式的,FAT16的格式化就是将上表中的格式数据写入到引导扇区中。上表中的数据并非每一行都有用,我们用到的有:BPB_BytsPerSec、BPB_SecPerClus、BPB_RsvdSecCnt、BPB_NumFATs、BPB_RootEntCnt、BPB_TotSec16、BPB_FATSz16。根据这些信息就能推断出GrapeOS的硬盘FAT16扇区分布:

3.FAT16目录项

文件夹也叫目录,文件和文件夹的属性都存储在目录项中,在根目录和其它目录中存放的是一个一个的目录项,也就是说文件夹的内容就是目录项列表。每个目录项有32个字节,具体结构如下:

名称 偏移 长度 描述
DIR_Name 0 11 文件名8字节,扩展名3字节
DIR_Attr 11 1 目录项属性(0x10代表文件夹,0x20代表文件)
保留位 12 10 保留位
DIR_WrtTime 22 2 最后一次写入时间
DIR_WrtDate 24 2 最后一次写入日期
DIR_FstClus 26 2 起始簇号
DIR_FileSize 28 4 文件大小

每个扇区可以存放16个目录项。

4.FAT表和FAT表项

前面我们讲到,在FAT16的数据区中是以簇为单位编号的,簇号从2开始依次递增。FAT16的簇号是用16位二进制数表示的,这也是FAT16中16的含义。除了前2个簇号不用,最后的16个簇号有特殊用途,FAT16最多可以管理216-2-16=65518个簇。
在目录项中,DIR_FstClus存放的是起始簇号。如果一个文件或文件夹的内容在一个簇里放不下,需要多个簇,其它簇号需要记录到FAT表中。在FAT16的FAT表中,每两个字节是一个FAT表项,每个FAT表项代表一个簇,从第一个FAT表项开始依次代表簇0、簇1、簇2、簇3、簇4等等,用来表示每个簇是否已被占用或下一个簇。对于每个FAT表项,如果它的值是0表示该簇未使用,可以用来存放新数据,对于一个刚格式化完的硬盘,FAT表中除了前2个表项,其它表项应该都是0。如果FAT表项的值不为0,表示该簇已被占用,而且这个值就是文件内容下一个簇的簇号,这样就实现了文件内容在数据区中的链式存储。从目录项中拿到文件的起始簇号,在起始簇号对应的FAT表项中的值就是存放文件内容的第二个簇号,在第二个簇号对应的FAT表项中的值就是存放文件内容的第三个簇号……举个例子,比如一个文件的起始簇号是5,在第5个FAT表项中存放的是文件内容的第2个簇号,假设第2个簇号是8,则会在第8个FAT表项中存放第3个簇号,以此类推,就像链表一样,直到下一个簇号大于等于0xfff8,表示文件内容结束,请见下图。

上图中表示这个文件共占用3个簇的空间,簇号分别是5、8、9。我们只要把这个簇链表中每个簇的数据从数据区里读取出来,并按簇链表的顺序存放在一起就是文件的完整内容。
FAT表项取值说明:

FAT表项 实例值 描述
0 0xfff8 磁盘表示字(实际无用,设为0即可。)
1 0xffff 第一个簇不可用(实际无用,设为0即可。)
2
3
……
0x0003
0x0004
……
0x0000:可用簇
0x00020xffef:已用簇,标识下一个簇的簇号<br>0xfff00xfff6:保留簇
0xfff7:坏簇
0xfff8~0xffff:文件的最后一个簇

前面我们已经提到,GrapeOS的FAT表有32个扇区,每个扇区有256个FAT表项,则共有8192个FAT表项。由于数据区簇号是从2开始的,FAT表中的前2个FAT表项不使用,也就是最多能管理8190个簇。我们这里一个簇等于一个扇区,所以这里的FAT表最多能管理8190个扇区。而我们这里的数据区共8127个扇区,FAT表大小够用了。


视频版地址:https://www.bilibili.com/video/BV16X4y1d7Ji/
配套的代码与资料在:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS操作系统交流QQ群:643474045

有关自己动手从零写桌面操作系统GrapeOS系列教程——22.文件系统与FAT16的更多相关文章

  1. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  2. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  3. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  4. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  5. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  6. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  7. ruby - 以毫秒为单位获取当前系统时间 - 2

    在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:

  8. ruby-on-rails - 如何测试自己对 Ruby/ROR 的了解? - 2

    是否有self验证的问题列表。看着那个,我可以确定我知道。我应该复习一下。在学习的过程中,我列了一个这样的list,但它只包含我在某处听说过的项目。我需要一段时间才能找到新的东西。 最佳答案 以下是针对ruby​​和Rails的一些测试列表。证书名称:RubyonRails谁提供:oDeskIncorporation认证费用:免费网站:https://www.odesk.com/tests/985?pos=0证书名称:RubyonRails提供者:Techgig.com(TimesBusinessSolutionsLimited(T

  9. ruby-on-rails - 如何构建复杂的 Rails 系统 - 2

    关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和

  10. ruby-on-rails - Rails 3,在RAILS_ROOT上方显示来自本地文件系统的jpg图片 - 2

    我正在尝试找出一种方法来显示来自不在RAILS_ROOT下(在RedHat或Ubuntu环境中)的已安装文件系统的图像。我不想使用符号链接(symboliclink),因为这个应用程序实际上是通过Tomcat部署的,而当我关闭Tomcat时,Tomcat会尝试跟随符号链接(symboliclink)并删除挂载中的所有图像。由于这些文件的数量和大小,将图像放在public/images下也不是一种选择。我查看了send_file,但它只会显示一张图片。我需要在一个格式良好的页面中显示6个请求的图像。由于膨胀,我宁愿不使用Base64编码,但我不知道如何将图像数据与呈现的页面一起传递下去。

随机推荐