Linux 深入理解文件(IO)

之前在学习C语言时,从语言层面对文件有了浅薄的理解,并不深刻,现在学习了操作系统,并对文件的学习进行了深化,不再是语言层,而是深入到系统,深入到底层去理解它。

文件读写的本质

再C语言中,我们学习过如何通过 fopen 函数来打开文件。

在Linux下,我们可以使用系统原生的 open 函数打开文件。

而C的 fopen 本质,是对系统的 open 函数进行了封装,所以调用 fopen ,其实是调用 open 来进行工作,同理的 fclose 也是封装了 close。

而我们打开文件的操作的本质,是进程打开文件,那么文件的路径问题就有了答案,而引入进程,我们也就可以尝试一窥文件的调用奥秘。

但在那之前,先补充一个概念,文件描述符。

文件描述符

在调用系统的 open 函数时,我们使用一个 fd 来接收其返回值。这个返回值就是文件描述符,其本质是一个从 0 开始的小整数,且优先使用当前最小的未被使用的整数。

当我们打开一个文件,操作系统需要在内存中创建相应的数据结构用来描述目标文件,这个数据结构是一个数组,而文件描述符就是这个数组的下标,数组里面存放着对应的一个文件指针,所以我们通过文件描述符,就可以找到对应的文件。

或许你无法很好地理解以上的解释,但没关系,先记住。

文件打开的底层结构

我们刚才说,打开文件本质是进程打开,那么会发生什么呢?

我们知道进程有一个 task_struct 结构体,也就是 PCB。PCB 里有一个 files 指针,这个指针又指向一个数组,叫做 files_struct ,也就是刚才说的,用来描述目标文件的数据结构,里面存放的就是我们的文件指针。我们通过一张图片来直观感受:

我们也可以通过一些代码来试着查看文件描述符:

上图中,我们试着打印 open 的返回值,但结果好像并不完全符合我们的预期。我们说了,文件描述符是一个从 0 开始的小整数,从代码运行的结果来看,fd 确实是一个小整数没错,但为什么我打开的第一个文件,它的文件描述符不是 0 而是 3 呢?而且当我关闭 test1 ,打开 test3,它的文件描述符也是 3,那岂不是说当前最小未分配整数是 3 咯!也从侧面证明,前面的 0,1,2 已经被占用。那么,谁占用了这前三个位置呢?

你可还记得,在C语言学习文件操作时,我们其实就知道,在程序启动时,系统会默认打开三个流,标准输入、标准输出、标准错误。而刚开始学习 Linux 时,也了解过一句话------" Linux下一切皆文件 "。没错,在Linux下,我们运行程序,系统也默认打开了这三个流,也就是文件,所以其实就是这三个文件,占用了文件描述符的 0,1,2 位置!

重定向的原理

原理

了解了文件底层的大概细节,现在不妨搞清楚我们开始学习 Linux 时了解到的重定向操作的实现原理。先来复习一下重定向操作,当时我们学习到的解释是 重定向是把本来输出到屏幕 / 从键盘读的数据,改成输出到文件 / 从文件读 ,这种简单的输出重定向 通过符号 > 来完成,此外还有追加重定向 >> ,输入重定向 <

而用我们现在的目光来开,重定向是做了一个什么工作呢?回到刚才说的文件结构,我们是通过文件指针来找到文件的,而找到文件指针使用到的就是那个数组的下标(文件描述符)。而重定向,其实就是对文件指针位置的改变,因为我们总不能改变数组下标的位置吧。

文件描述符 1 位置的是标准输出,我们可以暂时理解为显示器,接下来我们用 文件描述符 3 位置表示我们要重定向到的文件。那么重定向操作就是把 3 位置的指针覆盖到 1 位置就好了,就像这样:

重定向之后,在进程下,原来 1 位置的文件,也就是标准输出,会被关闭,如果后面还想用,得提前备份,比如保存到 10 位置。3 位置会被清空,不再指向文件。

dup2

我们之前用到的重定向操作符,其实是 shell 命令,所以我们只能在终端里使用它。如果想在代码里面使用重定向,我们需要使用到一个系统函数,dup2。

先来看看函数原型:

其中:

oldfd:要被复制的源文件描述符

newfd:目标文件描述符(如果它已经打开,会先被自动关闭)

成功返回 newfd ;失败返回**-1** ,并设置**errno。**

如果我们想用 dup2 实现 "把本来输出到屏幕,改成输出到文件",那么 oldfd 参数应该设置为 目标文件的 fd,newfd 设置为标准输出的 1。

相关推荐
小小的木头人37 分钟前
Ubuntu Samba修改端口绕过445封禁挂载
运维·ubuntu
wdfk_prog2 小时前
ROS教程:01 搭建 ROS1 Noetic Docker 开发环境
运维·缓存·docker·容器·ros
SEO_juper2 小时前
Java 并发编程实战:从线程基础到高并发架构
运维·人工智能·爬虫·chatgpt·seo
szephyr3 小时前
Docker + Compose 实战:把本地项目一键搬到云服务器,附完整配置
运维·docker·容器·部署·云服务器
wdfk_prog3 小时前
ros教程02:创建 catkin Workspace、Package 与第一个 ROS1 C++ Node
运维·缓存·docker·容器·ros
亚川楼宇自控系统数据中心厂家4 小时前
高校 / 医院 / 政务云数据中心 IBMS 系统怎么落地?
运维
陈陈CHENCHEN4 小时前
【Linux】服务器根目录磁盘扩容操作记录
linux·运维·服务器
GeW5 小时前
RHCE快速拿证全攻略:考点拆解+实验强化+时间规划,一次通关
linux
见闻小天地6 小时前
从晶片工艺到可靠性验证:晶威特TF-3215型RTC晶振全面解析
运维·业界资讯
沸速存储6 小时前
AI 机器人靠哪些内存与存储驱动整机运行?
服务器·科技·嵌入式硬件·电脑