计算机的文件系统就是操作系统储存组织计算机数据的方法,使用户操作的是直观的文件和目录结构,而不需要访问晦涩离散的数据块,在Linux中,文件系统中的文件是数据的集合,这里不仅包含文件中的数据,还有文件,目录,软连接等一系列相关的信息;文件系统就是对磁盘中的文件数据进行管理
文件系统结构层次
使用Linux的同学们一定听过这句话:“Linux下一切皆文件”,严格来说应该是除进程外,一切皆文件,这是Linux从Unix继承而来的哲学:Unix将一切资源都看作文件,包括硬件设备,并将被看作文件的硬件设备称为设备文件,而这样用户就可以用读写文件的方式实现对硬件的访问(举个例子,printf默认将文本数据写入标准输出文件stdout中,这一般就指的是计算机的显示屏设备,scanf则是由stdin指向的存放键盘输入数据的缓冲区里拿取数据)
-
硬盘驱动
常见的硬盘类型有PATA, SATA和AHCI等,在Linux系统中,对不同硬盘所提供的驱动模块一般都存放在内核目录树drivers/ata中,而对于一般通用的硬盘驱动,也许会直接被编译到内核中,而不会以模块的方式出现,可以通过查看/boot/config-xxx.xxx文件来确认:
CONFIG_SATA_AHCI=y -
General Block Device Layer
这一层的作用不同的硬盘驱动,会提供不同的IO接口,内核认为这种杂乱的接口,不利于管理,需要把这些接口抽象一下,形成一个统一的对外接口,这样,不管你是什么硬盘,什么驱动,对外而言,它们所提供的IO接口没什么区别,都一视同仁的被看作块设备来处理。
所以,如果在一层做的任何修改,将会直接影响到所有文件系统,不管是ext3,ext4还是其它文件系统,只要在这一层次做了某种修改,对它们都会产生影响。 -
文件系统
文件系统这一层相信大家都再熟悉不过了,目前大多Linux发行版本默认使用的文件系统一般是ext4,不管什么样的文件系统,都是由一系列的mkfs.xxx命令来创建,如:
mkfs.ext4 /dev/sda
mkfs.btrfs /dev/sdb
内核所支持的文件系统类型,可以通过内核目录树 fs 目录中的内容来查看。 -
虚拟文件系统(VFS)
Virtual File System:当我们通过mkfs.xxx系列命令创建了很多不同的文件系统,但这些文件系统都有各自的API接口,而用户想要的是,不管你是什么API,他们只关心mount/umount,或open/close等操作。
所以,VFS就把这些不同的文件系统做一个抽象,提供统一的API访问接口,这样,用户空间就不用关心不同文件系统中不一样的API了。VFS所提供的这些统一的API,再经过System Call包装一下,用户空间就可以经过SCI的系统调用来操作不同的文件系统。
VFS所提供的常用API有:
mount(), umount() …
open(),close() …
mkdir() …
文件存储结构
- 我们知道,文件数据最终是存储到硬盘上的上的,硬盘最基本的组成部分是由坚硬金属材料制成的涂以磁性介质的盘片,不同容量硬盘的盘片数不等。每个盘片有两面,都可记录信息。盘片被分成许多扇形的区域,每个区域叫一个扇区,每个扇区可存储128×2的N次方(N=0.1.2.3)字节信息。在DOS中每扇区是128×2的2次方=512字节,盘片表面上以盘片中心为圆心,不同半径的同心圆称为磁道。硬盘中,不同盘片相同半径的磁道所组成的圆柱称为柱面。磁道与柱面都是表示不同半径的圆,在许多场合,磁道和柱面可以互换使用,我们知道,每个磁盘有两个面,每个面都有一个磁头,习惯用磁头号来区分。扇区,磁道(或柱面)和磁头数构成了硬盘结构的基本参数,帮这些参数可以得到硬盘的容量,基计算公式为:存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
- 那么Linux/Unix又是如何管理这些空间的呢?
在存储系统上,一个文件或目录包含在一个块 集合中。有关文件的信息包含在一个 inode 中,它记录的信息包括所有者、上次访问文件的时间、文件的大小、它是否是一个目录,以及可以对它进行读写操作的对象。inode 号也称为文件序列号,且在特定文件系统内是惟一的。一个目录条目 包含一个文件名或目录名,以及存储有文件或目录相关信息的 inode 的指针。————Ian Shields
- 超级块:存放该文件系统本身的结构信息包括data/inode/块使用个数,未使用个数,inode bitmap /inode/data bitmap/data的区域大小/起始地址/结束地址;
- inode:也就是索引节点,每个索引节点对应一个文件/目录,它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息并存放目标data的data块的编号集合(因为一个文件会使用多个data块一起存储)可进行多级间接存储(我们以ext2文件系统为例);
- inode_bitmap:存储inode号,使用顺序表存储二进制位以表示inode的使用情况,按照偏移量对应每个inode的位置,需要用时就找那些空闲的inode号;
- data_bitmap:使用顺序表存储二进制位存放每个data块的位置和使用情况,当一个文件很大时,可以实现离散存储(虚拟地址空间的段页式效果)
- data: 文件的数据就保存在这个区域,该区域均匀分布着极多的大小默认为4KB(ext4下)的内存块,当文件大小超过4KB时,就可以分别存储在多个data block中,充分的利用存储空间并进行访问控制,但文件大小小于block大小时,该块将被标记为已使用,未销毁文件前不可再被其他inode使用;
当我们要创建一个文件时,会执行以下操作: - 从data_bitmap中获取到未使用的数据块,写入文件数据后,从inode_bitmap中获取一个未使用的inode节点,写入文件的详细信息和那些数据块的位置,然后再将文件的目录项写入所在的目录文件中
读取一个文件数据的操作: - 当我们需要读取一个文件的数据时,我们首先需要通过文件名(cat test.txt)获取到目录文件里存储的inode节点位置,进而在inode区中找到它,然后根据它储存的data块的位置对每个data块进行访问,从而获取数据
文件类型
Linux中文件类型有以下这几种:
1.-:普通文件。
2.d:目录文件,d是directory的简写。
3.l:软连接文件,亦称符号链接文件,s是soft或者symbolic的简写。
4.b:块文件,是设备文件的一种(还有另一种),b是block的简写。
5.c:字符文件,也是设备文件的一种(这就是第二种),c是character的简写。
6.p: 管道文件,FIFO也是一种特殊的文件类型,它主要的目的是,解决多个程序同时存取一个文件所造成的错误。FIFO是first-in-first-out(先进先出)的缩写。p时Pipe的简写(详细见:Linux:IPC(1)管道)
7.s:套接字文件,这类文件通常用在网络数据连接。
目录文件(d)中存放的是一张表:文件名与inode节点号,当你打开目录文件时:
使用Bookmark操作就可以直接读写这些文件,使用ls -i就可以查看这些文件的inode号或使用stat查看更加详细的信息:
链接文件
为什么要使用链接?
- 一个文件都有文件名和数据,这在Linux上被分为两部分:用户数据 (user data) 与元数据 (metadata)。用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方;而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块,而引入链接为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。
一个链接 仅仅是文件或目录的一个附加目录条目,允许同一文件或目录有两个或多个名称。一个硬链接 是指向 inode 的一个目录条目,而一个软链接 或符号链接 是指向提供另一目录条目名称的 inode 的一个目录条目。存储第二个名称所需的确切机制可能同时取决于文件系统和名称长度。符号链接也称为 symlinks。 ————Ian Shields
硬链接
- 通俗来讲:若一个 inode 号对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名/备份;删除文件时,node如果连接数大于1,inode状态不切换(从已使用切换到未使用就代表着存储的文件已经销毁)
- 创建:ln test.txt test.hard
软链接
- 本质是另外的一个单独文件中记录了源文件名字,进而让系统识别自动跳转到该文件位置进行操作
- 创建:ln -s test.txt test.soft
区别
- 软连接:单独文件.跟源文件没有区别;
- 删除源文件,硬链接文件,连接数-1;软链接文件失效
- 软链接文件可以跨分区创建,硬链接不可以,这是因为硬链接指向的inode在不同的文件系统分区里会冲突,而软链接所记录的路径则不会;
- 软链接文件可以针对目录创建,硬链接不可以,目录具有跨分区性;
文件描述符&文件流指针
- 在大致讲述了文件系统的构成之后,我们还要了解如何在一个进程中去访问文件
文件描述符
- 文件描述符是内核中struct file* fd_array的数组下标(一个正整数)—指向进程中的文件状态信息表中的文件描述信息(也就是它的索引);
- 按照惯例,Unix/Linux系统 shell 把文件描述符 0 与stdin(standard input)关联,文件描述符 1 与stdout(standard output)关联,文件描述符 2 与stderror(standard error)关联。
- 默认进程打开的描述符上限是1024,但仍可使用ulimit来进行修改;
- 文件描述符分配原则:最小未使用
- 重定向:重定向描述符,改变一个文件描述符的文件描述信息,改变了文件描述符所对应的文件描述信息此时对描述写入数据,改变了所要操作的文件。数据就从原本写入的文件流向了新的文件;dup2(text.txt,1)这里就是使用test.txt的文件描述信息替换了原本存放stdout描述符信息的fd_array[1];此后凡是要写入stdout的数据都会流入test.txt;
- 在Linux环境下,通常使用open/write/close/close这些系统接口通过文件描述符对文件进行操作
文件流指针
- C 语言中使用文件指针做为 I/O的句柄。文件流指针指向进程用户区中的一个被称为 FILE 结构的数据结构。FILE 结构包括一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄
- 在C库函数里通常使用fwrite/read/fopen/fclose,来通过文件流指针对文件进行操作;
联系
- 文件描述符是系统调用接口句柄,而文件流指针是标准库操作句柄;库函数封装了系统调用接口
注:
文件结构层次部分参考:http://soft.chinabyte.com/os/142/12315142.shtml
yo~
yo~
如果觉得不错~
请别忘了点个赞~
Bro你的鼓励~
给我坚持的勇气~
Peace out~