【基础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包裹着底层硬件的差异,给上层提供统一的文件操作接口,用统一的文件接口对不同的设备进行访问。这就是:一切皆文件!

相关推荐
绵绵细雨中的乡音1 小时前
网络基础知识
linux·网络
Peter·Pan爱编程1 小时前
Docker在Linux中安装与使用教程
linux·docker·eureka
kunge20132 小时前
Ubuntu22.04 安装virtualbox7.1
linux·virtualbox
清溪5492 小时前
DVWA中级
linux
MUY09903 小时前
应用控制技术、内容审计技术、AAA服务器技术
运维·服务器
楠奕3 小时前
elasticsearch8.12.0安装分词
运维·jenkins
Sadsvit3 小时前
源码编译安装LAMP架构并部署WordPress(CentOS 7)
linux·运维·服务器·架构·centos
xiaok3 小时前
为什么 lsof 显示多个 nginx 都在 “使用 443”?
linux
java资料站3 小时前
Jenkins
运维·jenkins
苦学编程的谢4 小时前
Linux
linux·运维·服务器