Linux文件系统和缓冲区


一、缓冲区

1.1 引入问题

我们先来解决一下上一篇文章最后,自己写的输出重定向,为何不能关闭自己打开的文件?即关闭文件后无法写入文件。

#include<stdio.h>                                                                                                            
#include<unistd.h>    
#include<sys/types.h>    
#include<sys/stat.h>    
#include<fcntl.h>    
int main()    
{    
  close(1);    
  int fd = open("./test.txt",O_CREAT|O_WRONLY,0644);    
  // 显然fd == 1占用了标准输出流    
  printf("fd = %d\n",fd);    
  printf("Hello World\n");    
  printf("Hello World\n");    
  printf("Hello World\n");    
  printf("Hello World\n");    
  printf("Hello World\n");    
  printf("Hello World\n");    
  printf("Hello World\n");            
 // close(fd); //先不关闭       
  return 0; 
}

先来看一下不关闭文件的情况,正常写入了自己打开的文件。
在这里插入图片描述
我们再关闭文件。
在这里插入图片描述
看一下结果,没有写进去,按道理来说,打开文件就要关闭文件,为什么没有写进去呢?这就要谈到缓冲区的概念了。
在这里插入图片描述

1.2 C语言的缓冲区

我们先来看一下整体缓冲区的示意图
在这里插入图片描述
用户层面有自己维护的缓冲区,例如C语言的缓冲区,使用printf标准输出的行刷新(’\n’),在C语言中文件的返回类型是一个FILE类型。C语言的所有操作都要通过系统调用。
在用户级写的数据存在用户级缓冲区,然后再经过一定的刷新策略,刷新到系统内核缓冲区,但是系统调用是直接写到系统缓冲区的。最后系统缓存的内容有操作系统刷新到真实存在的文件磁盘上。

我们可以加一个系统调用来看看:
在这里插入图片描述
发现系统调用写入了文件。
在这里插入图片描述

1.3 刷新策略

常见的有三种刷新策略

  • 无缓冲: 对数据进行操作时,不需要经过缓冲区,直接刷新在文件或显示器上。系统调用(wirte)没有附带缓冲区。
  • 行缓冲: 遇到\n就对缓冲区的数据进行刷新,这是对显示器而言。
  • 全缓冲: 缓冲区满了或者进程退出时才对数据进行刷新,这是对文件采取的刷新策略。

用户 到 0S 的刷新策略:

  1. 立即刷新(不缓冲)
  2. 行刷新(行缓冲\n),比如,显示器打印
  3. 缓冲区满了,才刷新(全缓冲),比如,往磁盘文件中写入

这样就可以解释上面的问题了,原本printf对应的标准输出流是打印到屏幕上,是行缓冲,但是被重定向为一个磁盘文件后,变成了全缓存,当关闭文件的时候缓冲区还没有满,是无法刷新到文件的,所以文件并没有对应的内容,系统调用可以直接刷新到系统缓冲区,然后写入文件。
那么用C语言写入文件,为什么可以正常关闭,关闭之后也能写入文件?
在这里插入图片描述

了解了刷新策略后,我们可以创建一个新的进程,看一下有什么效果。

在这里插入图片描述
在这里插入图片描述
所以创建子进程后,发生写时拷贝,然后子进程有一份和父进程一样的缓存区,因为C语言有自己的缓存区,并且往文件中写入是全缓存,所以系统调用先写入到了文件,子进程退出的时候写入了一份,父进程退出的时候也写入了一份。所以C语言函数的输出有两份。

总结:

  • 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。
  • printf fwrite 库函数会自带缓冲区(进度条例子就可以说明),当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。
  • 进程退出的时候,会刷新FILE内部的数据到OS缓冲区,然后写入文件
  • 但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。
  • write 没有变化,说明没有所谓的缓冲。

二、文件系统

2.1 inode

文件 = 文件内容 + 文件属性

文件被加载到内存中,在一个进程中有独立的编号fd,可以联想到在磁盘上,文件真实存储的地方,也会放上一个文件独立的编号,也就是inode编号,它是存放在inode里面的 。

可以详细打印一下相关的文件信息

在这里插入图片描述
在这里插入图片描述
最前面的一串数字就是文件的inode编号

学习inode之前需要看一下磁盘分区,磁盘空间很大,就像管理内存一样,也需要分区,每一个区有相应的管理结构,这样的话想要找到某个文件,就可以有目的的先找到对应的分区,然后查看分区管理结构,这样也提升了查找的速率。

下图是某个分区下的磁盘存储结构。是Linux特有的EXT系列的文件系统。

对于每一个分区来说,分区的头部会包括一个启动块(Boot Block),对于该分区的其余区域,EXT2文件系统会根据分区的大小将其划分为一个个的块组(Block Group)。启动块的大小是确定的,而块组的大小是由格式化的时候确定的,并且不可以更改。

其次,每个组块都有着相同的组成结构,每个组块都由超级块(Super Block)、块组描述符表(Group Descriptor Table)、块位图(Block Bitmap)、inode位图(inode Bitmap)、inode表(inode Table)以及数据块(Data Block)组成。

在这里插入图片描述

  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
  • GDT,Group Descriptor Table:块组描述符,描述块组属性信息
  • 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
    i节点表:存放文件属性 如 文件大小,所有者,最近修改时间等
  • 数据区(Data Block):存放文件内容

bitmap位图: 如 0000 1010 从右向左

  • 位置含义: inode编号
  • 内容含义:特定inode"是否"被占用!

目录也有inode,也属于文件。
linux下系统通过inode唯一标识一个文件(目录)

2.2 硬链接

我们看到,真正找到磁盘上文件的并不是文件名,而是inode。 其实在linux中可以让多个文件名对应于同一个inode。这就是硬链接。
对应命令ln filename filename-h
filename 是需要设置硬链接的文件名
filename-h 是设置的硬链接名

这里创建一个test文件
在这里插入图片描述
给它添加一个硬链接
在这里插入图片描述
可以发现它们的inode编号是一样的,也可以发现其中有一项信息改变了,那就是对应文件的硬链接数。即有多少个文件名指向这个inode
在这里插入图片描述
在删除文件时干了两件事情:

  1. 在目录中将对应的记录删除
  2. 将硬连接数减1,如果为0,则将对应的磁盘释放。

硬链接相当于一个文件的别名,与对应的inode建立了一个映射关系而已。
硬链接本质是根本就不是一个独立的文件,而是一个文件名和inode编号的映射关系,因为自己没有独立的inode !

2.3 软连接

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件。
指令ln -s filename filename-s
filename 是需要设置软链接的文件名
filename-s 是设置的软链接名

在这里插入图片描述
软链接还可以链接其他目录下的文件
在这里插入图片描述

软连接是有自己独立的inode的!软连接是一个独立文件!!!有自己的inode属性,也有自己的数据块(保存的是指向文件的所在路径+文件名)

取消链接unlink filename

软硬链接的区别总结

  • 软链接是一个独立的文件,有独立的inode,而硬链接没有独立的inode。

  • 软链接相当于快捷方式,硬链接本质没有创建文件,只是建立了一个文件名和已有的inode的映射关系,并写入当前目录

  • 硬链接的源文件和链接文件共用一个inode号,说明他们是同一个文件;而软链接原文件和和链接文件是不同的文件,链接文件inode指向的是源文件的绝对路径。

  • 硬链接在文件属性上体现不出来,其表示文件类型的字符处为“-”原文件是普通文件,硬链接文件也是普通文件;而软链接明确标识是链接文件,其表示文件类型的字符处为“l”。

  • 硬链接链接数目要增加,软链接的链接数目不会增加。

  • 硬链接文件大小跟原文件相同;软链接文件大小与原文件不同。

  • 硬链接有自己的文件名;软链接的文件名通常是指向其链接的原文件。

  • inode id只在本文件系统内有效,所以硬链接是无法跨越两个文件系统来建立链接的。软连接的则不同,因为新的inode中存储的是目标文件的路径,该路径是可以找到原始文件的inode的,所以可以跨文件系统建立。

  • 软连接一般有以下作用:

    • 1.当用户需要在不同的目录下用到相同的文件时,不需要在每一个目录下都存放该文件,只要在某个固定的目录下存放,然后在其它的目录下用命令链接( link)它即可,不必重复的占用磁盘空间。
    • 2.解决磁盘空间不足的情况。例如某个磁盘分区的空间已经快用完,但是现在必须在该磁盘分区下创建一个新的目录并存储大量的文件,那么可以在分区中建立指向另一个剩余空间较多的磁盘分区中目录的软链接,这样就能解决空间不足问题。

三、文件的三个时间

通过stat filename命令可以查看文件详细信息
在这里插入图片描述
这是文件的三个时间分别代表着什么意思呢?

  • Access: 最近一次的访问时间。(在较新的版本中,访问时间不会立即刷新而是有特定的时间间隔,由系统自动刷新,因为可能在短时间内非常频繁的访问文件)
  • Modify: 最近一次修改文件内容的时间。
  • Change: 最近一次修改文件属性的时间。

当我们修改文件内容的时候,很可能也修改了文件属性。

修改文件内容后,三个时间都发生了变化
在这里插入图片描述
touch filename可以刷新一个已经存在的文件的三个时间为当前时间。
在这里插入图片描述
浅谈一下,make命令如何判断可执行文件是否是最新?
在这里插入图片描述

  • 如果可执行文件的修改时间比源文件的新,那该可执行文件就是最新
  • 如果可执行文件的修改时间比源文件的旧,那该可执行文件就不是最新,可以执行make

伪目标就是不关心时间,可以一直被执行。


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s_persist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值