【Linux】fd_重定向本质

hello~ 很高兴见到大家! 这次带来的是Linux系统中关于基础 IO这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页 : 默|笙


文章目录

  • 一、理解重定向本质
      • [1.1 linux分配文件描述符遵循最小可用原则- - -分配规则](#1.1 linux分配文件描述符遵循最小可用原则- - -分配规则)
      • [1.2 IO函数只认文件描述符,不认特定的文件](#1.2 IO函数只认文件描述符,不认特定的文件)
      • [1.3 dup2系统调用](#1.3 dup2系统调用)
  • 二、初步认识一切皆文件

一、理解重定向本质

1.1 linux分配文件描述符遵循最小可用原则- - -分配规则

  1. 在之前的学习中,我们知道每一个进程运行之后,都会默认打开三个文件,分别是标准输入流,标准输出流和标准错误流,它们分别对应文件描述符0、1、2。而进程新打开的文件则会分配从3开始依次往后的文件描述符。
cpp 复制代码
 10   int fda = open("log.txt1", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 11   int fdb = open("log.txt2", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 12   int fdc = open("log.txt3", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 13   printf("fda: %d\n", fda);
 14   printf("fdb: %d\n", fdb);
 15   printf("fdc: %d\n", fdc); 
  1. 如果我们人为将这三个默认打开的文件关闭再打开一个新的文件log.txt会怎么样--->关闭标准输入流文件,那么文件描述符为0的位置就会空出来,这个时候3就不是最小且可以分配的文件描述符了,也就是说,log.txt的文件描述符会是0,而不是3。可以通过下面的代码进行验证:
cpp 复制代码
  9   close(0);                                                                                                                              
 10   int fp = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 11   printf("fp: %d\n", fp);

1.2 IO函数只认文件描述符,不认特定的文件

  1. C语言里面stdin、stdout和stderr都是对文件描述符fd的抽象封装,这也就意味着这三个流它们是不认识这些文件描述符所对应的文件的。一般stdin对应键盘文件,stdout和stderr对应显示器文件。如果将这些fd对应的文件替换掉,是不是就能够实现从其他文件进行输入输出了呢?是的。我们可以用下面这段代码进行验证:
cpp 复制代码
 10   close(1);
 11   int fp = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC);
 12   printf("fp: %d\n", fp);        
  1. 这里可以看到,如果我们把标准输出流关闭之后,printf要打印的内容在test执行之后没有显示在显示器上,而是打印到了log.txt文件里面,这是因为printf这个io函数它只认文件描述符1,它会把内容打印到文件描述符1对应的文件里面。在把标准输入流关闭打开一个新文件log.txt之后,文件描述符1就归log.txt这个文件了,printf要打印的内容自然就会打印到文件log.txt里面,而非显示器文件了。这就是为什么我们执行test看不到打印的内容而查看log.txt文件能够看到打印内容的原因。
  1. 我们通过关闭原来的输入输出流然后打开新的文件来代替要进行IO操作的显示器,键盘文件来实现对不同的文件输入输出。不过,现在一般是先打开新文件,然后将这个新文件覆盖掉原来的输入输出流对应文件。替换原输入输出流(键盘 / 显示器)对应的文件描述符(0/1/2)来达到对其他文件的IO操作,这就是重定向的本质
  2. 这里替换标准输入流对应文件也是一样,它不会再从键盘读取数据而是从文件描述符0对应的文件里面读取数据。
cpp 复制代码
 10   close(0);
 11   int fp = open("log.txt", O_RDONLY);                                                                                                    
 12   printf("fp: %d\n", fp);
 13   char s[10];
 14   scanf("%s", s);
 15   printf("%s\n", s);
  1. 事先我往已经存在的文件 log.txt 输入了一串字符helloworld,然后将文件描述符0对应的文件改为log.txt,之后用scanf读取log.txt文件内容再打印到显示器上,如果我们不改变文件描述符0对应文件,那么它应该从键盘读取数据,改变之后自然就从log.txt文件里面读取数据了。

1.3 dup2系统调用

  1. dup2这个接口就是专门用来改变文件描述符的,它的原理是进行覆盖,即用oldfd对应的文件覆盖newfd原本的绑定关系。比如上面我们用 log.txt代替了文件描述符0/1对应的文件,那么log.txt对应的文件描述符就是oldfd,而文件描述符0/1就是newfd。
  2. 有了这个函数,就不用通过关闭再打开文件进行替换操作,而是直接进行覆盖。
    10.进行程序替换是不会影响到进程已经打开的文件的。

二、初步认识一切皆文件

  1. 我们知道Linux系统里面一切皆文件,那么硬件在Linux系统里面也会是一个文件。OS要对这些硬件文件进行管理,一定也是先描述再组织,也就是把硬件的属性等其他内容打包成一个结构体struct_file。
  2. 对每个硬件进行操作,其实无非两种,输入和输出操作即IO操作。但是每一个硬件设备它们的访问方式都各不相同,比如键盘是输入,它的输出操作没有意义,显示器则与之相反。每一个硬件设备都有自己的输入和输出操作(驱动方法),要让OS对这些硬件以及其他文件进行统一操作,就需要对struct_file进行改造,加入operations模块绑定对应专属的IO操作,这样就实现了对不同的硬件进行统一操作。它类似于c++里面的多态。

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!

相关推荐
A小辣椒17 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒21 小时前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式