【Linux】访问文件的本质|文件描述符|文件重定向

前言:本文探讨的是操作系统中的文件本质,探讨“打开的文件”,与语言无关。

观察我们平时写的C语言文件操作的函数,例如:

FILE* fp = fopen("log.txt", "w");

可以发现返回值的类型是FILE* ,那么这个FILE*到底是什么?

FILE* 是C库自己封装的结构题FILE的指针

系统调用接口中,我们会使用下面的函数:

int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC);

可以发现返回值的类型是int,返回的内容是fd。这个fd我们称为文件描述符。

文件的结构

关于文件的结构,可以对比进程的结构,都i是差不多的。
当操作系统想管理文件的时候,需要做的是什么呢?
先把文件描述出来,然后再对大量的文件进行组织 — > 先描述再组织

对于文件,有很多属性,那我们就需要对每个属性进行封装,需要一个task_struct结构体对这些属性进行封装。

在task_struct中,有struct files_struct 结构体,这个结构体就是管理文件的。每创建一个文件,就在files_struct中进行一些操作(具体操作后面详细说明)。

那么,在task_struct中,想要对files_struct中进行操作,就需要有files_struct的指针,也就是 struct files_struct *f,这个指针操作files_struct。

在files_struct中有很多struct_file对象,每打开一个文件,就创建一个struct_file对象,在这个struct_file中存储的是什么呢?就是文件的各种属性:在磁盘的什么位置,基本属性,权限,大小,读写位置等,最重要的是struct_file * next指针,正是因为有了这个指针,就导致所有分离的文件通过链表的形式连接起来了。

现在我们已经知道struct_file对象通过链表连接起来了,就相当于一串一样,此时,在struct_file的上级 file_struct中是不是存了管理struct_file的指针。此时,在file_struct中创建一个数组,数组的内容就是存放指针,所以该数组是指针数组。数组的下标,我们就称为文件描述符,就是fd这个数组我们就叫文件描述符表。

在这里插入图片描述
这些都可以在操作系统的源码中看到

文件描述符

标准输入输出

在这里插入图片描述
运行结果:
在这里插入图片描述
根据结果可以发现文件描述符fd = 3。
为什么是3? 0,1,2去哪里了?
在这里插入图片描述
0号文件 —— stdin —— 标准输入
1号文件 —— stdout —— 标准输出
2号文件 —— stderr —— 标准错误

如何验证?

在这里插入图片描述
在这里插入图片描述
从这里可以看出0号文件确实就是stdin。

文件描述符的规则

在这里插入图片描述
上述代码中 close(1)表示的是将1号文件关闭。
接着,打开了一个叫做log.txt的文件。
将msg中内容写入到1号文件中。 1号文件是标准输出。

观察输出结果:
在这里插入图片描述
为什么我们明明是向1号文件中写入,不写入到标准输出(显示器)上,反而出现在了log.txt的文件中?

因为我们刚刚做了一个操作,是close(1),关闭1号文件。还记得我们之前有一个示例代码中打开文件,fd = 3,那时是因为0,1,2文件都被占用了,所以是3号文件。

现在1号文件的位置被腾出来了,所以新打开的文件就从前往后扫描,哪里空闲,就直接写入就行了。

这就是为什么向1号文件写入,却写进了log.txt中原因了。因为此时log.txt的文件的fd = 1.

本来如果不关闭1号文件,应该是如下图的结构
在这里插入图片描述
在关闭之后就变成下面这样了。
在这里插入图片描述

文件重定向

文件重定向有输出重定向,输入重定向,追加重定向,下面一一讲解。

输出重定向(对应符号’>')

其实上面的例子就是输出重定向。
在这里插入图片描述
所谓输出重定向,就是将本该输出到x的内容输出到y中。
操作:断开fd = i与文件x的链接,将fd = i 和 文件y重新建立连接。
上面的例子就是:本来应该输出到stdout中,但是由于将fd = 1和stdout的链接断了,并将log.txt链入到fd = 1中,所以输出就到了log.txt中。

echo的输出重定向

在这里插入图片描述
本来echo是向显示器中打印内容,现在:
将echo和stdout的链接断开,并重新建立echo和log.txt的链接
从而,可以将echo的内容打印到log.txt中。

输入重定向(对应符号’<')

同输出重定向一样,输入重定向就是将fd = 0 和stdin的链接断了,然后重新链接。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
上面的代码就是将stdin中的内容输入到buffer中。
我们将fd = 0和stdin的链接关了,并打开了一个文件test.txt,此时test.txt的fd = 0.
此时text.txt就是stdin
所以代码中将stdin写入到buffer中,其实是将fd = 0的文件的内容写入到buffer中,此时fd = 0的文件是test.txt,所以就是将test.txt的内容写入到buffer中。

追加重定向(对应符号‘>>’)

追加重定向和输出重定向的区别就是:
输出重定向会覆盖之前写的内容
追加重定向是在原本的内容之上进行追加,不会覆盖
在这里插入图片描述

结果:
在这里插入图片描述
最前面的字母是原来的,后面的汉字是追加的。

实现文件重定向的函数dup2()

dup2是实现文件重定向的函数,有了这个函数我们就不需要自己操作close(fd)再重新连接。

dup2的函数描述
在这里插入图片描述

参数

int dup2(int oldfd, int newfd)

可以看到有oldfd和newfd,该怎么理解?
oldfd就是我们准备重定向到的文件,在前面的例子中就是test.txt, newfd就是我们准备断开链接的文件,在前面的例子中就是1或者 0

函数解释:简单来说就是将oldfd的地址拷贝一份,让newfd指向oldfd的地址。

测试

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值