目录

一、文件描述符

二、IO重定向

三、重定向回终端、伪终端

四、恢复标准输入输出


一、文件描述符

在Linux中,文件描述符是一个非负整数的数据类型。是FILE结构体中的一个成员属性。 每打开或者新建一个文件时,内核都会返回最小的且未被使用的非负整数,即文件描述符。例如,文件描述符 0,1,2,4,5...已经被该进程使用了,那么再打开一个文件返回的文件描述符就是3,再打开一个新文件就是6。如果文件描述符被关闭,那么文件描述符在下一次可能会重新被打开。

FILE结构体大致如下

-----------FILE Structure---------
char fbuf[SIZE];
int counter,index..........   一些其它属性
int fd;  //文件描述符

Linux 为每个进程创建了文件描述符表(fd, 文件指针),其中文件指针,指向了系统级的打开文件表,通过该指针可以获取到文件偏移量和i-node指针信息,再通过文件偏移量和i-node指针,可以定位到文件系统中的i-node表,从而找到物理硬盘上的文件。换言之,在操作系统之上,通过进程号和文件描述符就可以定位到具体的文件。这个关系是一对多的,因为一个对象可以被多个指针指向,而一个指针只能指向一个对象。这就意味着,多个进程级的文件描述符可能会指向同一个系统级打开文件表,多个打开文件表项可能指向同一个i-node表。

二、IO重定向

在sh进程中有3个用于终端的IO文件流: stdin(标准输入),stdout(标准输出),stderr(标准错误)。

这3个流实际上指向文件结构体的指针, FILE * stdin , stdout ,stderr;

它们指向的FILE的区别在于它们的文件描述符分别是STDIN_FILENO, STDOUT_FILENO,STDERR_FILENO分别对应的值是0,1,2。标准输入默认来源于键盘,标准输出、标准错误的目标默认是屏幕。改变它们的来源或者目标就叫IO重定向。对应linux的操作符是   "<","1>","2>"。

所以通常程序的缺省情况,fd通常就已经打开了3个,如果想改变输入流或者输出流到文件,那么就要关闭对应的文件描述符。当重新open文件时,系统就会返回最小的且未被使用的文件描述符。

例如在filename.txt写入8878 . ,当关闭文件描述符0时,在打开文件,调用scanf函数就不再从键盘中输入,而把filename.txt中的内容当作输入。

#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
int main(){close(0);int fd = open("filename.txt",O_RDONLY);int item;scanf("%d",&item);printf("format= %d",item);
}

关于scanf。当FILE结构体中fbuf为空时,才会向内核中发出read系统调用,通过文件描述符为0 和进程号找到对应的文件,把文件数据读到fbuf中。所以哪个文件获取到了文件描述符0,那么标准输入的来源就是这个文件。同理,哪个文件获取到了文件描述符1  (2),那么标准输出(错误)的目标就是这个文件。

三、重定向回终端、伪终端

终端和伪终端通常包含屏幕和键盘。屏幕输出前,需要通常保存在/dev/ttyX  文件下 ,键盘输入后,输入的内容通常保存在 /dev/pts/# 下。

确定具体文件描述符打开的对应文件

例如在gdb调试代码时

通过   ps  -ef |grep a.out 找到进程号

查询   /proc/[进程号]/fd  中的内容  (需要root账号才可以登录fd目录)

查看到我的伪终端是:

/dev/pts/2

或者用 tty 命令查看伪终端

yu'shhi标准输入重定向回键盘:

 close(0);int fd = open("/dev/pts/2",O_RDONLY);

四、恢复标准输入输出

在/dev目录下有/dev/stdin 文件,stdout文件,stderr文件

注意:标准输入文件/dev/stdin是个链接文件!,其他也一样,它们存放的是文件描述符地址,链接文件类似指针,而标准IO文件类似于双重指针。文件描述符在Linux系统中也是一个链接文件。当close([文件描述符时]),其实删除的时文件描述符对应的链接文件。而/dev/stdin固定链接每个 /proc/self/fd/0,当0被删除了之后,/dev/stdin也就链接成了空文件。

也就是说下述代码得到结果并没有重新获得键盘输入

#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
int main(){close(0);                                /**文件 /proc/[pid]/fd/0 消失*****/ int fd = open("filename.txt",O_RDONLY);  /**文件 /proc/[pid]/fd/0 链接上了filename.txt */       int item;scanf("%d",&item);                       /*stdin 找到/proc/[pid]/fd/0 中读数据*/close(0);                                /*文件 /proc/[pid]/fd/0消失,/dev/stdin为空链接*///这样做的意图是 /dev/stdin -> /proc/self/0 -> /dev/stdin 吗??? 显然目的不是这样的int fd = open("/dev/stdin",O_RDONLY);    /*打开空链接文件,并非是终端文件*/scanf("%d",&item); printf("format= %d",item);
}

所以如果要保证代码的通用性,变更stdin链接之前需要把终端文件用新的文件描述符保存起来。

(1)  int fd = dup(oldfd);   ,     int fd= dup2(oldfd,newfd);

当调用dup函数时,内核在进程中创建一个新的文件描述符,此描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项
  dup2和dup的区别就是可以用newfd参数指定新描述符的数值。
  APUE用另外一个种方法说明了这个问题:
  实际上,调用dup(oldfd)等效于,fcntl(oldfd, F_DUPFD, 0)
  而调用dup2(oldfd, newfd)等效于,close(oldfd);fcntl(oldfd, F_DUPFD, newfd);

查看如下代码:

#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
int main(){int fd2=dup(0) ;    //复制文件描述符0对应的表项给fd2 = 3,此时fd2 ,和0 都指向终端close(0);           //关闭文件描述符0int fd = open("filename.txt",O_RDONLY); //filename.txt获取文件描述符0 int item;scanf("%d",&item);                //从标准输入0中读数据printf("format1= %d\n",item);    //输出filename.txt中读出来的内容dup2(fd2,0);                      //复制文件描述符fd2表项给0,此时0重新指向终端,// fopen("/dev/stdin", "r+");      scanf("%d",&item);                //同时意味着/dev/stdin 也间接指向了终端printf("format2= %d\n",item);
}

Linux C:文件描述符、IO重定向、恢复标准输入输出相关推荐

  1. 【Linux】文件描述符与重定向

    重定向符号 符号 描述 > 输出重定向到一个文件或设备 覆盖原来的文件 >! 输出重定向到一个文件或设备 强制覆盖原来的文件 >> 输出重定向到一个文件或设备 追加原来的文件 ...

  2. 玩转linux文件描述符和重定向,玩转Linux文件描述符和重定向

    本文介绍linux中文件描述符与重定向的相关知识,文件描述符是与文件输入.输出相关联的整数,它们用来跟踪已打开的文件.有需要的朋友参考下. 原文出处: linux下的文件描述符是与文件输入.输出相关联 ...

  3. 玩转Linux文件描述符和重定向

    本文介绍linux中文件描述符与重定向的相关知识,文件描述符是与文件输入.输出相关联的整数,它们用来跟踪已打开的文件.有需要的朋友参考下. 原文出处:http://www.jbxue.com/arti ...

  4. linux 反弹shell(一)文件描述符与重定向

    0X00 前言 由于在反弹shell的过程中有一些非常精简的语句,但是一直没有深入理解,只是作为一个伸手党/搬运工,于是下定决心要将其弄明白,而这里面最难的也就是文件描述符和重定向的部分,因此我特地写 ...

  5. Linux Shell 文件描述符 及 stdin stdout stderr 重定向

    Abstract: 1) Linux Shell 命令的标准输入.标准输出.标准错误,及其重定位: 2)Linux Shell 操作自定义文件描述符: 文件描述符是与文件相关联的一些整数,他们保持与已 ...

  6. STDOUT_FILENO文件描述符的重定向及还原 (dup2函数用法) Linux系统编程

    在重定向之前保存默认文件描述符,在向text文件写入后再还原STDOUT_FILENO描述符 #include<stdio.h> #include<stdlib.h> #inc ...

  7. linux下文件描述符的介绍

    linux下文件描述符的介绍 (2012-10-02 16:01:56) 转载▼ 标签: 描述符 调用 返回 进程 限制 it 分类:linux 当某个程序打开文件时,操作系统返回相应的文件描述符,程 ...

  8. linux 文件指针,Linux中文件描述符fd与文件指针FILE*互相转换实例解析

    本文研究的主要是Linux中文件描述符fd与文件指针FILE*互相转换的相关内容,具体介绍如下. 1.文件描述符fd的定义:文件描述符在形式上是一个非负整数.实际上,它是一个索引值,指向内核为每一个进 ...

  9. Linux下文件描述符

    Linux下文件描述符 标签: linuxfilelinux内核apacheunixsocket 2012-08-17 15:45 5798人阅读 评论(0) 收藏 举报 分类: 调优和安全(5) 版 ...

  10. 深入理解Linux/Unix文件描述符和epoll

    Linux/Unix 文件描述符(File Describer)的本质 Linux/Unix(以下简称Linux)系统中,每个进程都有一个专用的数组,数组的元素是一个结构体,称为文件描述符File D ...

最新文章

  1. 数字图像缩放之最近邻插值与双线性插值处理效果对比
  2. java求最大公约数(分解质因数)
  3. hiho #1044 : 状态压缩·一
  4. 微软 CTO 韦青:对微软这样已经走过44年的公司,现在也只是个小小小的开始!!!
  5. 关于基本工作素养在职场当中的重要性
  6. HTTP协议详解 (转)
  7. 台式机也应该设置为WIN10节能模式
  8. N54L文件服务器,N54L安装群晖需要修改的硬件设置
  9. 100%解决VMware虚拟机NAT上网方式,保姆教学
  10. 华为交换机最常用的基础命令汇总大全,赠最新版华为S系列交换机调试配置指南
  11. mysql数据库面试题学生表_SQL笔试题:下面是学生表(student)的结构说明
  12. 微信小程序UI设计(一)之开发前言
  13. android 以太网 热插拔,android_8.1 hdmi设备热插拔事件
  14. stripe 海外支付
  15. POJ 2240 HDU 1217 Arbitrage(Floyd)
  16. Cortex-A 系列处理器
  17. 智慧燃气系统基于GIS技术的搭建
  18. 回调函数举例ajax,通过回调函数的理解来进一步理解ajax及其注意的用法
  19. 协和医院(东单院区)就诊流程记录
  20. 关于奖金压缩的一种算法

热门文章

  1. C++ STL学习之容器set和multiset (补充材料)
  2. ci 框架插入时返回插入的id号
  3. expandableListView 总结
  4. springmvc国际化
  5. 【C++】关于随机函数与概率设置
  6. SQL SERVER 2005无法远程连接的问题
  7. 尽管普通的sql语句代码可以实现数据插入的操作,但是更好的代码应该是参数的方式:...
  8. MySQL优化 之 Discuz论坛优化
  9. moss 2007 单点登录的配置
  10. harbor-offline-installer-v2.1.0.tgz 分享