系统编程--Linux下文件的“其他操作”函数

文件存储理论补充

dentry、inode

在这里插入图片描述

首先我们知道,inode,在创建硬链接的时候用到过,如下图:
在这里插入图片描述
当我们创建一个文件的硬链接时,该硬链接会有一个与文件一样的Inode

但是Indoe是什么:
Inode是一个结构体,存储着文件属性的结构体,他会存储一个文件的各种属性,以及“该文件在磁盘中的位置”,但是没有存储文件名

而dentry,存储着文件名+该文件的inode,相当于是一个目录,其名字也是"目录项"

当我们描述一个文件时,首先会根据dentry,找到他的inode,之后就知道了该文件的各种属性,而通过inode记录的文件的磁盘位置,就可以看到文件的内容了

而我们平时创建硬链接的底层原理是:
在这里插入图片描述
创建一个硬链接,就会创建出一个dentry,其文件名就是硬链接的文件名,匹配的就是目标文件的inode,这样就建立了硬链接,这也是为什么硬链接会与原文件有相同的inode

而删除硬链接,以及删除文件:
在这里插入图片描述
删除硬链接,其实就是删除dentry,删除一个dentry,其硬链接计数就会减一

当删除完所有的硬链接,然后又删除了文件,那么就会把所有的dentry都删除了,那么这个文件的inode就没有dentry引用了

但是此时,在磁盘中的文件安然无恙,也就是说,删除文件并不会真正的去磁盘中删除文件,而这个磁盘的内容,只有在没有dentry引用其inode的情况下,会被其他文件所覆盖,覆盖了才是真正意义的删除

数据恢复:
在这里插入图片描述
如果磁盘文件内容还没有被覆盖,我们就可以对该部分数据再次建立一个inode以及dentry,就可以做到对数据的恢复

文件其他操作

stat函数

man 2卷

作用

获取文件的各种属性

函数原型

在这里插入图片描述
参数一:文件路径(精确到文件名)
参数二:传出参数,指向struct stat类型的变量的指针

其中 stat结构体的内容:(实际上就是inode的内容,也就是我们平时ls -l (小L)显示的内容)
在这里插入图片描述

在这里插入图片描述

代码(以获取文件大小为例)

在这里插入图片描述
最终在sbuf结构体中已经有了该文件的所有属性,想打印哪个就打印哪个

这里我们打印文件的大小,这个可以实现与“lseek获取文件大小”相同的效果,且该方式是推荐的方法

注意使用%ld进行打印,其类型为unsinged long int

补充(获取文件类型)

在这里插入图片描述
拿到stat结构体变量中的数据后,在该结构体中有一个st_mode属性,利用该属性,配合其提供的宏函数,我们可以完成上图中的一些判断(如判断该文件是否是一个普通文件、还是一个目录?…)

而宏函数一般只返回0或1,也就是返回真或者假,他会告诉你是或不是

代码:
在这里插入图片描述

但是:
当我们测试其他类型没有问题,但当我们测试“符号链接”类型时,出现了问题:

首先我们创建两个符号链接:
在这里插入图片描述
在这里插入图片描述

结果是:在这里插入图片描述

可以看到,最终打印的都是符号链接所指向的最终的实体文件,该现象称为stat穿透,默认情况下stat是穿透的,如何解决,看下一个函数

lstat函数

作用

解决stat函数的“穿透”现象

函数原型

与stat函数原型一样

代码

在这里插入图片描述
与stat函数使用规则一样,只不过加了一个 “l” (小L)

结果:
在这里插入图片描述

在这里插入图片描述
实际上,我们的vim、cat,都是穿透的(作用到最终指向的实体文件)
而ls -l 是不穿透的 (作用于“链接本身”)

补充(获取文件权限)

在这里插入图片描述
在man中的demo没有使用宏函数进行文件类型的判断,而是使用了位运算

简单解释一下:
这里还是用到了位图:
在这里插入图片描述
一个位图,有2字节,16位,从右向左,每三个为一组,一共三组,共9位,分别代表不同组的文件权限(用户、用户组、其他用户)
再往左三位是特殊权限位
最开始的四位是文件类型,四位,转为八进制其总数就是17(即017,0是八进制的前缀)

上图中的S_IFMI就是017,也就是其二进制为1111 000 000 000 000,由于他前面都是1,所以可以作为掩码使用,所以st_mode & S_IFMT,最终得到S_IFMT下面的宏,就对应其表示的信息,由此可见,使用该方式,不仅可以获取到文件类型(宏函数可以获取),还可以获取到不同组的执行权限等信息(宏函数获取不到):
在这里插入图片描述

总结

在这里插入图片描述
因为lstat与stat没有其他区别,而且lstat不会进行穿透,所以,以后我们直接使用lstat就可以了

tips

在这里插入图片描述
在一些重要的函数的man手册中,我们点击“G”,会跳到最下面,这里可能会有一个当前函数的demo示例

link函数

man 2卷

作用

在这里插入图片描述
我们之前创建硬链接,都是通过命令行的ln命令,但是在代码中,我们不可能去到终端敲命令,所以就有了link函数,他就是负责创建硬链接的,实际上,是为文件新建一个dentry项

通过上面这张图我们也能知道,硬链接不像软链接,他在ll时,并不会表现为链接文件名,而是类似于创建了一个新文件,这也符合硬链接的原理:创建多个dentry,指向inode,所以,一个文件被刚创建时,系统就自动的为其创建了一个dentry,这就是我们常见的文件

简介

在这里插入图片描述
建立硬链接,也就是新建dentry项,而使用mv命令修改文件名时,也是修改了dentry,并不对真正的文件做操作(利用原先的dentry,创建出一个新的dentry,之后将原先的系统创建的dentry删除,就完成了文件的改名)

函数原型

在这里插入图片描述
参数一:原先的文件的dentry路径(精确到文件名)
当我们创建一个新的文件时,系统在磁盘写入了文件之后,会自动创建一个dentry,这个就是我们平时看到的文件

参数二:新的dentry路径(若没有,系统自动创建,一般是没有,因为硬链接都是新建的)

代码(模拟mv命令进行文件重命名)

在这里插入图片描述

效果:
在这里插入图片描述
先利用原先系统创建的dentry,建立新的dentry,之后将原先的那个删掉,使用unlink函数,直接传入文件路径即可

unlink

作用

解除一个硬链接(或者当前文件只有一个dentry时(也就是硬链接计数为1,即文件刚创建的状态),对当前文件进行“删除”(只是让其具备删除条件))

简介

在这里插入图片描述
可以看到,这里也说了,当一个文件的目录项(dentry)没有时,该文件会被操作系统择机释放,因此,我们删除一个文件,只是让文件具备了被释放的条件,什么时候释放,由系统决定,且打开该文件的进程必须关闭了,才能被释放

代码

需求:我们要在一个程序运行时,创建并打开一个文件,在程序结束时,这个文件要被销毁

在这里插入图片描述
在这里插入图片描述
我们在程序的末尾,在return之前,将该文件unlink掉,就可以实现上述的需求了

在程序第35行,设置了一个getchar(),该函数的作用是与用户进行IO交互,这里相当于“阻塞”,阻塞程序,不让程序结束,这样可以方便我们进行测试,(例如在另一个终端查看程序未结束时,那个临时文件在不在)

但是,假如说我们的程序在执行到39行之前,程序崩了,那么无法执行后续的代码便使得主函数退出了,这样的话,那个临时文件就不会被删除,如下图:
在这里插入图片描述
假如说,我们在34行,对p这个只读变量进行写入操作,那么会发生段错误(访问非法内存,或更改只读变量),程序崩溃,由此一来,那个临时文件不会被删除

如何解决:
在这里插入图片描述
直接将该部分unlink代码,放到open后面

我们不用担心在这里把临时文件unlink掉之后,后续的代码就找不到文件了,这个是不会的,因为unlink,只是将dentry删除,文件还在磁盘,等待所有使用该文件的进程结束了,系统才会择机释放,当前进程使用着临时文件,所以该文件不会被释放,仍然存在,这样,就不怕后续发生程序崩溃导致unlink没执行了

而如果程序正常进行,此时就算有阻塞,我们开另一个终端去查该临时文件,也是找不到的,而向该文件写入的内容,是被写入到了内核缓冲区里面

补充:隐式回收

问题产生

在这里插入图片描述
我们程序发生了段错误,程序崩溃,后续的close没有执行,那这个fd会一直占用着系统资源吗(占位符3,0、1、2是标准输入输出出错)

解决问题

在这里插入图片描述
答案是不会,因为程序的进程一旦被退出,那么该进程所有的内存资源都会被回收,这一过程称为“隐式回收”,也就是一个进程被关闭时,所有的内存会被释放(包括泄露的和不泄露的),但是也不能忽视内存泄漏,因为很多程序是一直处于开启状态进行监听的,程序一直运行,无法关闭,就无法隐式回收

readlink

在这里插入图片描述
在我们创建一个软链接后,其软链接的大小是指:创建连接时,敲入的链接文件的路径,被他当做字符串存了起来

而我们如何查看一个已有的软链接的指向呢,使用cat是不行的,因为他会进行穿透

所以使用一个命令:readlink,就可以拿到软链接链接的文件路径(创建时使用的相对路径会显示相对路径,创建时使用的绝对路径,就会显示绝对路径)
在这里插入图片描述
该命令也有一个函数,将结果返回到缓冲区buf中

rename

在这里插入图片描述

  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值