在计算机出现之前其实就有文件系统的概念了,此时的文件系统指的是用于管理(存储和检索)纸质文件的系统,而在计算机发明之后,文件系统逐渐指的是管理存储介质的系统,它通过简单的接口给用户,方便用户使用存储设备。
在学习 Linux 的时候,我们通常会看到这样一句话,Linux中一切皆文件,也就是说,不管是普通的文件和目录,还是包括块设备、管道、socket等,也都是交给文件系统去管理的。文件系统是操作系统中负责管理持久数据的子系统,换言之,也就是负责把用户的文件存到磁盘硬件中,它是一个磁盘上的目录结构,是一个组织文件的方法,并且在一个磁盘上,可以包含一个或者多个文件系统。
下面,我们从用户的角度和操作系统的角度两个层面来阐述文件系统的相关概念。
要认识 Linux 的文件系统,从分区和目录结构说起,首先我们先来看下windows,这是大多数人使用最多的一个操作系统,当打开我的电脑的时候,映入眼帘的是大致是这样一个一张图:
image-20210606083453663
也就是说在 windows 下,磁盘被分为了 C 盘, D 盘。。。。这样的一个目录结构。那对于 Linux
呢,它的目录结构是长啥样,它有一个根目录,而系统下的所有目录都是从根目录分离出去的,我们可以在 Ubuntu
终端运行如下命令来查看Linux
的目录结构。
tree -L 1 /
上述中,tree
表示将当前目录以树的结构展示,-L
表示的是要显示当目录的第几层,1
表示的是要显示到第一层,最后面的 /
表示的也就是Linux
的根目录,也就是说当前命令就是显示根目录下第一层目录的信息,最终得到的结果如下所示:
image-20210606084251803
为了更好地理解每个目录所代表的意思,我们看如下所示的内容:
/
|----bin ----------------> 文件系统的起始位置,称之为根
|----boot ----------------> 存放系统启动时读取的文件,包括系统核心文件
|----dev ----------------> 存放设备文件接口,如打印机,硬盘等外围设备
|----etc ----------------> 存放与系统设置和管理相关的文件,如用户账号、密码等
| |
|----home -----------------> 存放用户专属目录
|----lib -----------------> 存放一些共享的函数库
|----misc -----------------> 一个空目录,供管理员存放公共杂物
|----proc -----------------> 存放系统核心和执行程序之间的信息
|----root -----------------> 系统管理员(超级用户)专用目录
|----sbin -----------------> 与 /bin 类似,存放用于系统引导和管理命令,通常供 root 使用
|----tmp -----------------> 临时目录,供任何用户存放临时文件
|----usr -----------------> 此目录包含许多子目录,用来存放系统命令和程序等信息
|----var -----------------> 存放经常变动的文件,如日志文件,临时文件,电子邮箱
说到这,就有必要再说一下 Linux
下的路径问题了,在Linux
中,Linux
的路径分为绝对路径和相对路径
/
和~
开始的路径均为相对路径说完了路径,接下来要叙述的就是 Linux
的文件类型的,Linux 内一切皆文件,那么对于 Linux 来说,其具有哪些文件类型呢,其主要有如下四种:
windows
下的快捷方式,它本身不包含内容,而是指向其他的文件或目录/dev
目录下,如:hda,hdb,sda。。。最后,在平时使用操作系统的时候,可能会涉及到挂载的操作,那挂载是什么意思呢?Linux
启动的时候,首先挂载的是根文件系统,之后可以自动或者手动挂载其他文件系统,这些文件系统要挂载到挂载点上,与虚拟文件系统和通用块设备层建立联系。
挂载,指的就是将设备文件中的顶级目录连接到 Linux 根目录下的某一目录(最好是空目录),访问此目录就等同于访问设备文件。
上述就是基于用户的角度对文件系统进行了一个概述,接下来从操作系统的角度,更进一步地阐述操作系统。
在上述中,阐述挂载的时候说到一个概念,就是说 Linux
在启动的时候,首先挂载的是根文件系统,然后再自动或者手动挂载其他文件系统,这也是Linux
中支持不同文件系统的原因,而支持各种不同文件系统的这种机制又是什么呢?说到这里,就有必要提到Linux
的虚拟文件系统了,再叙述它的概念之前,我们先以宏观的角度来看一下 Linux
下的文件系统的一个结构:
image-20210606105240091
由上图可以知道,整个文件系统体系分为了三个层面,用户层,内核层,硬件层,用户层是通过API通过系统调用调用的方式访问虚拟文件系统。在内核层,我们可以看到虚拟文件系统下连接了各种类型的文件系统,其是对不同的文件系统的抽象,为上层应用提供了统一的 API 接口;上图内核层还有一层是各个文件系统之下的一层,这一层的作用是隐藏了不同硬件设备之间的细节,为内核提供了统一的 IO 操作接口。下面我们对整个文件系统从下到上对各个层的作用进行一个阐述:
PATA,SATA
,在Linux
中,对于硬盘提供的驱动模块一般都存放在内核目录树drivers/ata
中,而对于一般通用的硬盘驱动,可能会直接被编译到内核中。Linux
使用的是ex4
,与此同时,btrfs
也呼之欲出上述中,我们介绍了文件系统的层次,那么基于这样一个层次,我们又应该如何使用文件呢?下图是一个使用文件的流程图:
image-20210606131958026
与其对应的代码也比较简单:
fd = open(name, flag); /* 打开文件 */
...
write(fd, ...); /* 写数据 */
...
close(fd); /* 关闭文件 */
上述就是往一个文件中写数据的步骤,使用open
系统调用打开文件,open
的参数中包含文件的路径名和文件名,使用write
写数据,其中write
使用open
所返回的文件描述符,使用完文件后,用close
系统关闭文件,避免资源的泄露。
在打开了一个文件后,操作系统会跟踪进程打开的所有文件,也就是说操作系统为每个进程维护一个打开文件表,文件表里的每一项代表的是文件描述符,所以说文件描述符是打开文件的标识。
image-20210606133042481
操作系统在打开文件表中维护着打开文件的状态和信息:
根据文件系统的读写差异,可以将IO分为四种类型:
此处标准库缓存指的是利用栈、队列等一些数据结构进行的资源调度,而不是页缓存。无论是否是缓冲IO,都会通过系统调用页缓存来减少IO次数
根据是否利用操作系统的页缓存,可以把文件I/O分为直接I/O与非直接I/O
通常,我们的 IO 都是非直接I/O
根据应用程序是都阻塞自身运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O
通常情况下I/O都是阻塞的。网络编程中是非阻塞的I/O,用在网络套接字的 I/O 中
根据是否等待响应结果,把文件分为同步IO和异步IO
Linux
中所有文件都有一个唯一与之对应的索引节点,索引节点记录了文件的元数据,操作系统不是通过文件名,而是通过索引节点来管理文件,用目录项来描述文件之间的关系。
索引节点,也被称之为是inode,用来记录文件的元数据,元数据就包括:node编号、文件大小、访问权限、修改日期、数据的位置等。
目录项,也被称为dentry
,用来记录文件的名字、索引节点指针及与其他目录项的关联关系。多个关联的目录项,也就构成了文件系统的目录结构。
因此,索引节点相当的于文件的指针,目录项维护着文件的树型关系
下面是文件存储各个部分逻辑关系的一个示意图:
image-20210606145357280
上图中,超级块用来存储着整个文件系统的状态,索引节点区用来存储索引节点,数据块区用来存储文件的数据,他们之间的关系在图中也很清除了,就不进行赘述了。
Linux
是一个很庞大也很优秀的系统,在嵌入式行业也应用广泛,笔者对于 Linux
的接触不深,这也是最近对于学习 Linux
文件系统时的一个总结,如果文中出现问题,欢迎各位及时给我提出来呀,我将不胜感激~