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。

相关推荐
阿洛学长23 分钟前
VMware安装虚拟机教程(超详细)
java·linux·开发语言
YOU OU27 分钟前
Linux基本使用和程序部署
linux·运维·服务器
AI行业学习35 分钟前
PuTTY 工具下载部署、基础配置及 SSH 远程服务器连接完整操作指南Windows 平台 【2026.6.1】
运维·windows·ssh
jiayong2336 分钟前
CI/CD深度解析01-核心概念与原理
运维·git·ci/cd
fred_kang36 分钟前
如何找到 Linux 服务器上某个 URL 路径对应的实际部署位置
linux·运维·服务器
用户2367829801681 小时前
Linux iptables 深度解析:从规则匹配到 NAT 转发实战
linux
CairBin2 小时前
SideSail——Ubuntu 26.04(GNOME 50)侧边栏插件,支持设备信息剪贴板和米家设备简单控制
linux·ubuntu
Jempo M2 小时前
小品文:服务器并发模型深度解析:从原理到实践
服务器
howard20052 小时前
3.4 Linux目录操作
linux·目录操作
tedcloud1232 小时前
codegraph部署教程:构建代码库语义分析环境
服务器·人工智能·word·excel