自己动手从零写桌面操作系统GrapeOS系列教程——22.文件系统与FAT16
学习操作系统原理最好的方法是自己写一个简单的操作系统。
新买的硬盘和优盘在第一次使用时需要格式化,有时候还需要分区。这是为什么呢?分区和格式化到底是干啥呢?本讲将为大家解开这些疑惑。
一、文件系统
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://space.bilibili.com/1688387238
配套的代码与资料在:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS操作系统交流QQ群:643474045
自己动手从零写桌面操作系统GrapeOS系列教程——22.文件系统与FAT16的更多相关文章
- 别人写的一个Bootstrap系列教程
http://www.cnblogs.com/lansy/category/659061.html
- 一个人写的操作系统 - Sparrow OS
一个人写的操作系统 - Sparrow OS 自己写一个操作系统,这是在过去的几年里我一直为之努力的目标,现在终于完成了. 缘起 自己动手写操作系统的动机最初来自于学习Linux遇到的困难. 我是一个 ...
- 自制 os 极简教程1:写一个操作系统有多难
为什么叫极简教程呢?听我慢慢说 不知道正在阅读本文的你,是否是因为想自己动手写一个操作系统.我觉得可能每个程序员都有个操作系统梦,或许是想亲自动手写出来一个,或许是想彻底吃透操作系统的知识.不论是为了 ...
- 【操作系统】关于Linux桌面操作系统
以前是Win+Ubuntu+黑苹果,周末想体验一下deepin,于是简单安装了一下,安装过程很简单,这里不再描述.安装之后,第一次打开系统,确实很惊艳,赏心悦目的操作系统. 之前用Ubuntu时候,C ...
- 盘点|2021年最受欢迎Linux桌面操作系统前十名
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 阿里云开源镜像站利用云服务上的优势,提供快速.稳定的镜像分发服务.和免费的CDN加速服务.更新频率高,基本上一天一更新,对于Centos/Ubun ...
- 手把手教你从零写一个简单的 VUE
本系列是一个教程,下面贴下目录~1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 今天给大家带来的是实现一个简单的类似 VUE 一样的前端框架,VUE 框架现在应 ...
- 《一步一步写嵌入式操作系统》读书笔记1—Skyeye介绍、安装和HelloWorld
2013-11-14 最近在看<一步一步写嵌入式操作系统>,感觉此书甚好,许多地方讲得很清楚.可操作性强,计划边读边实践边写笔记,希望能够逐步熟悉嵌入式操作系统底层的东西,最终剪裁出一套实 ...
- Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)
我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...
- Zedboard学习(一):移植Ubuntu桌面操作系统 标签: ubuntu移植zedboardFPGA 2017-07-04 21:53 26人阅读
环境准备: 首先,需要的肯定是Ubuntu操作系统.可以在自己的电脑上安装物理机,也可以是虚拟机下运行的.我的是在Vmware下运行的Ubuntu14.04 32位操作系统. 由于zedboard上的 ...
- 27、从零写UVC驱动之分析数据传输(设置ubuntu通过串口打印,指定打印到文件,ubuntu切换root用户)
A. 设置ubuntu让它从串口0输出printk信息a. 设置vmware添加serial port, 使用文件作为串口(在vmware中设置,文件是保存在windows中)b. 启动ubuntu, ...
随机推荐
- sublime Vue、ejs、less、scss高亮展示
sublime中默认不支持ejs.vue.less.scss等文件高亮展示.解决办法可以增加对应插件: 一.安装: 1.打开sublime 2.点击 preferences ->Browse ...
- 关于*p++的执行顺序
不确定*p++哪个优先级高了,想偷懒到百度找找解释,发现高赞的评论下也骂声一片,还是回头自己试试. 1 #include <iostream> 2 using namespace std; ...
- sequelize关联相关表
在article的迁移文件: 在commemt里面添加: 在单条查询里面 这样一个文章里面包含一个评论
- 基于Python接口自动化测试持续集成----在jenkins创建任务->检出git的代码-->生成报告-->发送邮件
步骤一:先在jenkins创建一个自由风格的任务 步骤二:然后在源码管理选择git检出代码的方式,需要提供代码所在git的路径和登录git的账号和密码 步骤三:返回到任务配置的界面,先在构建后操作增加 ...
- HDFS、Ceph、GFS、GPFS、Swift、Lustre……容器云选择哪种分布式存储更好?
HDFS.Ceph.GFS.GPFS.Swift.Lustre--容器云选择哪种分布式存储更好?-51CTO.COM 容器云在使用分布式存储时,HDFS.CEPH.GFS.GPFS.Swift等分布式 ...
- antd EditableProTable 组件的简单用法
首先,antd EditableProTable 组件是在 table组件的基础上又封装了一层,可以实现行更新,删除,增加.只需动动手指,简单配置一下即可. 先下载 EditableProTable ...
- 井字棋判断输赢C
#include <stdio.h> int main(){ char a[3][3]; for (int i = 0; i < 3; ++i) { for (int j = 0; ...
- 关于lesscss和颜色梯度(linear-gradient )的一些问题
一.什么是less? 一种 动态 样式 语言. LESS 将 CSS 赋予了动态语言的特性,如 变量, 继承,运算, 函数. LESS 既可以在 客户端 上运行 (支持IE 6+, Webkit, F ...
- Linux 常用杂项命令
1.查看监听端口的进程名称 lsof -i:[3306] # 3306是端口名称 2.查看PID进程文件的位置 ls -al /proc/51955/exe # 51955是进程PID
- 在.NET中使用JWT
1.配置文件添加 //jwt配置文件 "JWT": { "SigningKey": "14fa5f2rrwsg627fs256fdgff2r5rf52 ...