【基础IO⑨】:重定向实现原理 &&“Linux下一切皆文件“

【基础IO⑨】:重定向原理 与 "Linux下一切皆文件"

一.重定向

我们首先关闭2号文件描述符,然后再打开一个文件log.txt。并且打印这个文件的文件描述符。最后我们将发现这个文件的文件描述符是2。

这是为什么呢?很简单,因为文件描述符的填充是从上往下,从0开始填没有被占用的位置,因为2号位置被关闭了,所以普通文件log.txt就被放进2号里面了。

我们知道三个标准输入输出流stdin,stdout,stderr分别代表这键盘文件,显示器文件,显示器文件。它们默认是被打开的,也就分别占用着0,1,2文件描述符。

当我们再打开一个文件时,就默认占用的是3号文件描述符。

不过如果我们利用上面的原理,先关闭一个文件,那么这个文件描述符位置上就空缺了,然后再打开一个文件,那么这个文件就会被填到原来的文件的位置里去。

比如先将1号描述符位置上的文件关闭,即将显示器文件关闭。然后再打开普通文件,这时,1号描述符位置上的文件地址就变成普通文件了。

然后我们当向1号描述符输出时,就会重定向输出到普通文件里。

1.实现原理

实现重定向的原理其实就是覆盖文件描述符里文件地址。因为文件描述符是不变的,只能改变文件描述符里面的文件地址。原来1号描述符指向的显示器文件,如果1号描述符里的显示器文件地址被覆盖成普通文件地址,那么1号描述符就指向普通文件。当我们往1号描述符输出时,就会输出到文件里。

所以重定向的本质就是:文件描述符数组里的内容拷贝

不过这样写有点low,先关闭一个文件,再打开一个文件。因为重定向的本质就是文件描述符数组里面文件地址的拷贝,所以系统提供一些系统调用接口,可以帮助我们直接拷贝:

dup2(int oldfd,int newfd)接口的功能就是让oldfd作为拷贝对象拷贝给newfd。其实就是让oldfd文件描述符里的文件对象拷贝给newfd文件描述符里的文件对象,最后newfd文件描述符就指向了oldfd文件描述符指向的文件了。

2.输出重定向

当我们往1号描述符里输出时,就会输出到普通文件里,而不是输出到显示器上。这就是输出重定向。

3.输入重定向

当我们从0号文件符里获取输入时,本来是从键盘上获取输入,但是却从文件里获取到了输入内容,这就是输入重定向。

注意:

1.printf里封装的是1号描述符,它只知道往1号描述符里的文件对象输出,但它并不知道1号描述符里的文件对象是谁,也不关心是谁。

2.

4.补充:简易shell中实现重定向

在重定向之前需要先打开文件,这样才可以获取对应的文件描述符,才可以利用文件描述符重定向。

并且在进行重定向过程中,进程如果发生程序替换是不会受影响的!

二."Linux下一切皆文件"

Linux下一切皆文件,这句话你是不是在学习Linux中不断的听过,但是你理解它吗?为什么在Linux下一切皆文件呢?

首先我们先理解:

1.所有的操作计算机的动作都是以进程的形式进行的。

2.所有访问文件操作都是直接通过进程方式访问的。

3.每一种外设硬件都有自己的方式去读写。虽然方法都不一样,但方法种类却类似,都是读和写。

Linux在上层不关心底层访问的是什么设备,不管是键盘,还是显示器,还是网卡等都看成文件。以文件的方式读写访问设备。

Linux中是如何做到这样的呢?

1.虚拟文件系统(VFS)

我们知道当进程访问文件时,操作系统会给这个文件创建一个文件对象。这个文件对象的地址会被放进文件描述表里。

操作系统创建的文件对象会以链表的形式链接起来,而这软件层

被称为虚拟文件系统VFS。

因为硬件都有自己的方法读写,虽然方法不同,但却有共性。那么我们就可以将这个共性组成一个结构体,里面存储着函数指针,分别是读函数指针和写函数指针。当调用具体函数指针时,就会去调用对应的方法。

而这个结构体称为 操作方法指针集。里面的指针分别指向对应的外设自己的读取方法。

所以每打开一个文件,操作系统还会创建一个对应的读取方法集对象。这个结构体对象里存着许多函数指针,分别对应着底层外设的读写方法。

当你要打开键盘时,操作系统就将键盘的读写方法初始化这个方法集对象,这样调用这个方法集对象里的具体函数指针就是键盘的访问操作。

当打开的是显示器,操作系统就会将显示器的读写方法初始化给方法集对象,调用方法集对象里的函数指针就能正确的使用显示的读取方法。

而在文件对象里存储着方法集对象的指针,可以通过该指针找到方法集对象,继而可以调用对应的外设访问方法。

所以Linux是如何不需要管底层设备是什么,都可以按照文件的方式进行访问呢?

1 . 因为在打开的每个文件对象里都有对应的指针指向方法集结构,里面的函数指针可以找到对应访问外设的正确方法。

2 .所以在进程看来,它可能不知道调用什么方法访问外设,但只要创建了文件对象,那么这个文件对象里就有指针可以找到对应的方法集。所以进程想要访问谁,只需要打开对应的文件。

所以哪和设备想被打开,想被访问,也就是要将自己的设备读取方法给文件对象。文件对象里会存储一个指针,指向方法集合。

不管是什么设备,只要操作系统创建出来对应的struct file对象。就可以正确访问该设备。

因为操作系统会将该设备的读取方法初始化给方法集对象。而文件对象里有有一个指针可以指向方法集对象。

总结:

操作系统启动时会创建一个软件层VFS,当外设要打开时,就会创建对应的文件对象,就会创建对应的函数指针对象,将函数指针初始化为底层设备具体的方法操作。

每种设备都有对应的struct file对象,都有函数指针对象。函数指针指向不同的方法。所以进程不管是什么设备,直接通过文件对象里函数指针对象里函数指针,调用读_函数指针获取读操作,写函数指针获取写操作。所以在上层直接调用read和write就可以访问底层的读写方法,里面肯定是这样封装的:

所以软件层VFS包裹着底层硬件的差异,给上层提供统一的文件操作接口,用统一的文件接口对不同的设备进行访问。这就是:一切皆文件!

相关推荐
一瓢一瓢的饮 alanchan1 小时前
【运维监控】influxdb 2.0 + grafana 11 监控jmeter 5.6.3 性能指标(2)
运维·jmeter·grafana·监控·influxdb·运维监控
CodeHackerBhx2 小时前
如何使用VMware安装Linux操作系统
linux·运维·服务器
小阿轩yx2 小时前
小阿轩yx-通过state模块定义主机状态
linux·云计算·运维开发·state定义主机状态·jinja模板
PythonFun2 小时前
如何快速找回Finalshell中VPS的SSH密码
运维·ssh
花果山~~程序猿4 小时前
高级I/O知识分享【5种IO模型 || select || poll】
运维·服务器·网络
Pakho love4 小时前
Linux:软件包管理器 yum和编辑器-vim使用
linux·编辑器·vim
吴半杯5 小时前
Linux-mysql5.7-mysql8.0安装包下载及安装教程,二合一
linux·运维·服务器
默行默致5 小时前
Linux 常用命令
linux·运维
码哝小鱼5 小时前
firewalld实现NAT端口转发
linux·网络
RememberLey5 小时前
【VitualBox】VitualBox的网络模式+网络配置
linux·网络·virtualbox