learn-tech/专栏/计算机基础实战课/34文件仓库:初识文件与文件系统.md
2024-10-16 10:18:29 +08:00

190 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
34 文件仓库:初识文件与文件系统
你好我是LMOS。
通过之前的学习相信你或多或少都体会到“Linux之下一切皆文件”的思想了。
数据是以文件的形式储存下来的而文件数量一多就需要文件系统来管理文件而文件系统正是建立在之前我们学过的IO块设备之上今天我就带你了解一下什么是文件什么是文件系统。
还是延续之前的风格,学习过程中有动手实践的部分。这节课的配套代码,你可以从这里下载。让我们正式开始今天的探索之旅吧!
什么是文件
在日常生活中,我们提到的文件通常是指公文、信件,而计算机中的文件与日常见到的文件载体不同,是以计算机硬盘为载体、存储在计算机上的信息集合。
这些信息集合的呈现形式非常多样,可以是文本文档、图片、音乐、视频、应用程序等。文件通常由文件名进行标识和索引。
只说个概念的话你很难对文件是什么有更深的理解所以下面我们写代码建立一个文件感受一下。Linux把建立文件的操作包含在了open调用中open调用既可以打开一个已经存在的文件又可以建立一个新文件代码如下所示
int main()
{
int fd = -1;
// 打开并建立文件,所有用户可读写
fd = open("empty.file", O_RDWR|O_CREAT, S_IRWXU|S_IRWXO|S_IRWXG);
if(fd < 0)
{
printf("建立文件失败\n");
return -1;
}
// 关闭文件
close(fd);
return 0;
}
上面的代码很简单我们建立一个名为empty.file的文件但是你需要注意的是我们并没向该文件中写入任何数据并且你可以在当前目录下看到该文件的大小为0
这说明了文件不一定要有数据它只是一个标识这个标识可以既标识数据设备还可以标识接口/proc目录下的那些文件其实内核提供给进程的用来访问特殊数据的接口)。
现在我们再给文件下个定义就可以说文件从广义上就是一种资源标识或者对象标识
我们继续基于前面的代码完善一下给向程序里写三个字节的数据并且获取一下文件大小代码如下
int main()
{
struct stat filestat;
int fd = -1;
char ch[] = {0, 1, 0xff, 'L', 'M', 'O', 'S'};
// 打开并建立文件,所有用户可读写
fd = open("empty.file", O_RDWR|O_CREAT, S_IRWXU|S_IRWXO|S_IRWXG);
if(fd < 0)
{
printf("建立文件失败\n");
return -1;
}
// 向文件中写入3个字节010xff它们来源于ch数组
write(fd, ch, 3);
// 获取文件信息比如文件大小
fstat(fd, &filestat);
printf("文件大小:%ld\n", filestat.st_size);
// 关闭文件
close(fd);
return 0;
}
接下来我们运行代码看看运行结果如下图所示
从截图里我们看到了文件大小为3同时我们打开empty.file文件观察里面的内容也会发现是三个字节与我们在代码中定义的一样看到这个现象我们应该明白了从狭义说常规文件是一个信息数据集合单位是字节
我们继续修改代码写入7个字节看看是什么情况这里我们只需要修改write调用里的第三个参数把它改为7就行了代码我已经为你改写好了我们直接看运行结果如下所示
同样地我们看到了文件大小为7再次打开empty.file文件同样也是七个字节与代码中定义完全一样对字符数据是存储它对应的ASCII码
看到这里你有没有对文件产生什么新的思考呢有没有发现所谓普通文件的结构本质上是一个可以动态增长的线性字节数组无论文件是什么类型或者多大的数据都会映射到对应的字节占用一个或者多个字节空间
我们现在理解了文件是一种标识也推理解出了文件储存数据的结构是什么样子但是我不知道你有没有想过描述一个文件自身也需要很多信息我们可以把这些信息称为文件元信息
比如上面用来表示文件大小的信息就是文件的元信息不过文件不光有大小的信息还有其它别的元信息
我们继续来修改代码试着获取文件的部分元信息为什么是部分元信息呢因为在应用层有些元信息我们是获取不到的操作系统也不会提供相应接口修改后的代码运行情况如下所示
上图中dev表示文件所在的设备号而rdev则是当文件是设备类型时的设备号文件模式能表示文件或者目录文件节点则表示该文件在文件系统中对应的inode号码
inode是文件系统中标识一个文件的元信息上面这些信息大多都来自inode结构这些信息访问修改状态改变的时间是以秒为单位的上面的数据相同是因为我们在一瞬间完成了文件的创建和修改用户id和用户组id则表示该文件是哪个用户建立的属于哪个用户组
文件除了本身大小在文件系统中还分成了块来存储所以文件有块大小和文件占用了多少块这些信息下面我们通过一幅逻辑结构图总结一下什么是文件
由上图可知普通文件的元信息中不仅仅保存了文件相关的设备时间创建者大小等相关信息还保存了文件数据块的索引信息这样才能找到这些数据块这也从侧面证明了一个普通文件必须有两个部分组成一个部分为文件元数据一部分为文件储存的数据
文件在硬盘上以块为单位储存这些块的块号在元信息中按照顺序索引起来就是整个文件的数据这就是一个普通的数据文件普通数据文件的信息都存在储存设备上这个设备通常是硬盘或硬盘分区硬盘的一部分)。
如果只有一个软件我们只要确定元数据和文件数据分别放在哪些扇区就可以无论是查找读写删除怎么处理都很容易不幸的是文件不可能只有一个而是有成千上万甚至更多所以这就必须要设计出一套系统方案来解决多个文件的操作管理
接下来我们就聊聊文件管理系统它是操作系统中一个巨大的功能模块
文件系统
我们先来搞清楚文件系统概念文件系统是操作系统在存储设备常见的是硬盘U盘CD或者其分区上构建的储存文件方法和数据结构也就是在存储设备上组织文件的方法由于这个功能模块规模很大操作系统专门起了一个名称把负责管理和存储文件的功能模块称为文件管理系统简称文件系统
文件系统由三部分组成分别是文件系统的接口对文件操作和管理的功能集文件及其属性
从操作系统角度来看文件系统的职责是组织和分配存储设备的空间文件存储以及对存入的文件进行保护和检索具体点来说文件系统给用户提供了文件相关操作的一条龙服务包括为用户建立存入读出修改转储文件控制文件的存取读取文件当用户不再使用时还会删除文件
一个硬盘中的各个分区上可以使用不同的文件系统但是在使用之前我们要对该分区进行格式化所谓格式化就是向该分区写入文件系统相关的信息以及分配分区中相关扇区的数据结构有了这些数据结构和信息用户应用才能在文件系统里存放文件
虽然文件系统的核心数据结构现在我们还没法直观地感受到但是它在上层为用户或者进程提供了一个逻辑视图也就是目录结构这是一个倒置的树形结构
树的分支结构上是目录或者文件从最上层的 /目录开始就能找到每个文件每个目录和每个目录下的所有文件目录对文件进行分层分类目的是方便用户对众多文件做管理我为你画了一幅图来展示这个结构如下图所示
如上图所示这是一棵倒树根据上图中的各种路径就可以找到其中的任意文件或者目录例如我们在系统中输入:/home/user1/file1这就表示其根“/”目录下home目录里的file1文件
了解了文件系统的逻辑结构之后我们不妨进一步思考一下假如让你来设计实现一个文件系统你会怎样梳理它的结构呢
我们先得设计描述整个文件系统信息的结构其次要有描述目录的信息结构然后是描述文件元信息结构最后别忘了文件数据块结构其实Linux上众多文件系统都是这么实现的即使各文件系统在细节上有些变化但是都具有类似的通用结构其中心概念离不开超级块目录结构inode节点以及数据块下面我们分别进行讨论
让我们从数据块说起由于文件系统数据结构也是存放在数据块中的所以第一个就要把它搞清楚
对于这么多文件系统设计文件系统首先会把硬盘或者硬盘分区划分为一个个数据块每个数据块大小是硬盘扇区的整数倍典型的数据块大小是1024字节或者4096字节
这个大小既可以在格式化硬盘或者硬盘分区创建文件系统的时候决定也可以由管理员手动指定还可以在文件系统的创建时根据硬盘分区的大小动态选择一个较合理的值
我们再来看看超级块超级块一般会放在硬盘分区的第一个或者第二个数据块中超级块中的数据是描述文件系统的控制信息
有关该文件系统的大部分信息都保存在超级块中比如硬盘分区中有多少个数据块每个数据块的大小有多少个空闲数据块文件系统状态有多少目录或者文件文件系统名称UUID位图信息等这些信息可以用来控制和描述一个可正常工作的文件系统
接下来要说的是目录结构目录结构很简单里面就是文件名称和inode号组成的目录项一个目录项可以是另一个目录也可以是一个文件所有的目录项共同组成了目录文件特殊的文件)。根据目录项的inode节点号我们就可以找到对应的文件的inode那inode是什么呢我们接着往下看
之前的课程里已经讲过文件数据都存放在数据块中我们还必须使用一个数据结构来存储文件的元信息这种存储文件元信息的数据结构叫做inode即索引节点也经常叫作inode节点)。其实刚刚我们讲文件的时候就提过inode记不清的话你自己再回顾一下
每一个文件都有对应的inodeinode包含了文件的元信息也就是说除了文件名以外的所有文件信息都保存在inode之中文件名称在目录条目中主要有文件的字节数文件的所属uid文件的所属组GID文件的读执行权限以及文件的创建修改时间等
最重要的是inode节点中包括数据块的地址用于索引文件对应的数据但inode节点中只有少量数据块数的地址如果需要更多就需要动态分配指向数据块的地址空间这些动态分配的数据块是间接地址数据块为了找到数据块必须先找到间接地址数据块的然后从里面找到文件的数据块地址
有了上述四大核心结构就可以表示一个文件系统了其实Linux对超级块结构目录结构inode结构以及数据块还做了进一步抽象把这些结构加入了操作函数集合形成了VFS即虚拟文件系统
只要软件模块能提供上述四大核心结构的操作函数集合生成超级块结构就可以形成一个文件系统实例安装到VFS中有了VFS层就可以向上为应用程序提供统一的接口向下兼容不同的文件系统让Linux能够同时安装不同的文件系统
我为你画了一幅图表示其架构如下所示
你有没有发现在计算机科学领域的很多问题都可以通过增加一个中间的抽象层来解决上图中 Linux VFS 层就是应用和许多文件系统之间的抽象层
VFS 向下规范了一个文件系统要接入 VFS 必需要实现的机制为此VFS 提供了一系列数据结构如filessuperblockdentryinode结构还规定了具体文件系统应该实现生成这些数据结构的回调函数这样一个文件系统模块就可以被安装到 VFS 中了操作具体文件时VFS 会根据需要调用具体文件系统的函数
从此文件系统的细节就被 VFS 屏蔽了应用程序只需要调用标准的接口就行了也正因如此Linux 可以支持 EXTXFSBTRFSFATNTFS 等多达十几种不同的文件系统但不管在什么储存设备上使用什么文件系统也不管访问什么文件都可以统一地使用一套类似 open()、read()、write()、close() 的接口
关于VFS我们就介绍到这里更详细的VFS讲解你可以参考我的另一门课程:《操作系统实战 45 中第三十五节课[《瞧一瞧Linux虚拟文件系统如何管理文件?》]。
重点回顾
这节课我带你了解了文件和文件系统
文件是一种资源对象的标识可以标识最简单常见的数据文件也可以标识一个设备或者一种访问内核的数据接口普通文件有许多元信息和数据块组成它们通常保存硬盘中的扇区中
而文件数量一多就需要文件系统来管理文件系统为应用程序提供了一个逻辑视图具体是一棵倒立的树结构方便用户管理众多文件
为了把众多文件存储到硬盘中文件系统用一棵倒立的目录树来存放各种类型的文件从根目录开始就可以找到所有的目录和文件其次我们还了解到了文件系统的内部概念如超级块目录结构inode节点数据块等
Linux系统为了支持多种类型的文件系统还进一步抽象出了VFS任何文件系统模块只要符合VFS对数据结构和操作函数集合的要求都可以安装到VFS层中VFS的出现使得Linux支持多种文件系统成为可能
我还给你准备了一张导图你可以做个参考
看到这里我知道你意犹未尽或者还有许多疑问我们将在下一节课深入探讨EXT文件系统的内部实现细节相信那时你会对文件系统是怎么一回事有个更深的理解
思考题
一般的Linux上的文件系统都有哪些内部结构
期待你在留言区分享你的学习收获或疑问如果这节课对你有帮助别忘了分享给更多朋友说不定就能让他对文件系统有个新认识