总结了Linux操作系统中I/O重定向问题
涉及open、close、dup、dup2系统调用

参考资料


1. I/O重定向

1.1 Linux中的文件描述符fd:

文件描述符代表一个文件,他是进程级的。在进程PCB中存在着一张文件描述符表,也可以叫做打开文件描述符表。这张表每个进程都会有且为进程独有,所以它是进程级的。这张表上的每一个表项都由两个部分组成,文件描述符标志以及一个文件指针。其中文件描述符标志也就是我们所使用的文件描述符fd,也可以将其看做是这张表的下标。
内核(kernel)利用文件描述符(fd)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。文件描述符这一概念往往只适用于UNIXLinux这样的操作系统。

在Linux下,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据流stdin/stdout/stderr

  • stdin的文件描述符是0

  • stdout的文件描述符是1

  • stderr的文件描述符是2

由于linux中的一些涉及底层的程序编写往往会围绕着文件描述符展开,因此我们只需要将其他文件(如一个新打开的文件)的文件描述符替换为0/1/2(即替换掉stdin/stdout/stderr的文件描述符),就可以完成I/O重定向。使得原本针对标准输入输出流文件进行的操作变为针对其他文件的输入输出操作。

1.2 重定向标准输入

用一个新打开的文件替换文件描述符0(原本是stdin的文件描述符),那么输入将来自该新文件而不是标准输入流

1.2.1 close系统调用

close()函数关闭文件描述符(使之成为未使用的文件描述符,后面其他文件可以使用该fd)并释放相应的内核资源,成功返回0,出错返回-1

int close(int fd);

参数fd是要关闭的文件描述符。需要说明的是,当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件。但是对于一个长年累月运行的程序(比如网络服务器),打开的文件描述符一定要记得关闭,否则随着打开的文件越来越多,会占用大量文件描述符和系统资源。

1.2.2 open系统调用

open()函数会打开一个文件,并使用最小的未使用的文件描述符数值作为文件描述符(因此一般是从3开始,然后4,5,6一直下去)成功返回文件描述符,失败返回-1

int open(const char *pathname, int flags,mode_t mode);
  • 参数path是要打开或者要创建的文件路径

  • 参数flags用于指定文件的打开/创建模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)、O_CREAT (如果文件不存在则创建)、O_APPEND(追加)等

  • 第三个参数mode仅当创建新文件时才使用,用于指定文件的访问权限位,如八进制数字如0777,表示文件所有者、该文件用户组、其他用户都有可读可写可执行权限。

1.2.3 使用close与open系统调用完成重定向标准输入

文本文档log.txt

the num is 123

源文件main.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(){close(0);//关闭文件描述符0int fd = open("./log.txt",O_RDONLY);//只读打开一个文件printf("the fd is %d\n",fd);char str1[10],str2[10],str3[10];int num ;scanf("%s %s %s %d",str1,str2,str3,&num);//从文件描述符0代表的文件输入数据printf("the text content is : %s %s %s %d\n",str1,str2,str3,num);
}

运行结果

xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ gcc main.c
xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ ./a.out
the fd is 0
the text content is : the num is 123

可以看出,新打开的文件的文件描述符fd是0,即成功替换了stdin的文件描述符。scanf从文件描述符0代表的文件输入数据,由于完成重定向标准输入,导致scanf函数从新打开的文件获取输入。

1.2.4 dup系统调用

dup复制文件描述符df到数值最小的未使用的文件描述符。如果复制成功返回最小的尚未被使用的文件描述符,若有错误则返回-1。返回的新文件描述符和参数oldfd指向同一个文件,共享所有的锁定,读写指针,和各项权限或标志位。

int dup(int oldfd);

示例:使用dup完成重定向标准输入

文本文档log.txt

the num is 123

main1.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(){int fd = open("./log.txt",O_RDONLY);//只读打开一个文件printf("the fd is %d\n",fd);close(0);//关闭文件描述符0int newfd = dup(fd);//进行dup系统调用printf("the new fd is %d\n",newfd);char str1[10],str2[10],str3[10];int num ;scanf("%s %s %s %d",str1,str2,str3,&num);//从文件描述符0代表的文件输入数据printf("the text content is : %s %s %s %d\n",str1,str2,str3,num);
}

运行结果

xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ gcc main1.c
xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ ./a.out
the fd is 3
the new fd is 0
the text content is : the num is 123

可以看出在代码开头先通过open系统调用只读打开一个文件,由于此时还没有close掉0号文件描述符,因此给新打开的文件分配文件描述符3。紧接着close掉0号fd使得0成为最小的未使用文件描述符,通过dup系统调用使文件描述符0与3指向同一个文件,并成功通过scanf从0号fd获取输入内容。

1.2.5 dup2系统调用

dup2**系统调用将fd1复制到fd2中,如果fd2已经打开,则先关闭它。newfd和oldfd共同指向一份文件。**成功返回newfd,失败返回-1。如果newfd等于oldfd,则dup2直接返回newfd, 而不关闭它。

int dup2(int oldfd, int newfd);

示例:通过dup2系统调用完成重定向标准输入

文本文档log.txt

the num is 123

main2.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(){int fd = open("./log.txt",O_RDONLY);//只读打开一个文件int newfd = dup2(fd,0);printf("the oldfd is %d , the newfd is %d\n",fd,newfd);char str1[10],str2[10],str3[10];int num ;scanf("%s %s %s %d",str1,str2,str3,&num);//从文件描述符0代表的文件输入数据printf("the text content is : %s %s %s %d\n",str1,str2,str3,num);
}

运行结果

xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ gcc main2.c
xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ ./a.out
the oldfd is 3 , the newfd is 0
the text content is : the num is 123

可见dup2系统调用关闭了文件描述符0,并使得文件描述符0与3指向相同的文件,从而能够通过scanf从文件描述符0代表的文件获取输入内容。

1.3 重定向标准输出

重定向标准输出的原理与重定向标准输入一样,只不过是替换掉stdout的文件描述符1

1.3.1 通过close与open系统调用进行重定向标准输出

main3.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(){close(1);int fd = open("./log1.txt",O_WRONLY|O_CREAT);//创建并只写打开文件printf("%s %s %s %s %d","this","is","a","file",fd);
}

运行结果

xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ gcc main3.c
xtark@xtark-vmpc:~/桌面/linux_study/section3/io test$ ./a.out

log1.txt

this is a file 1

可见成功重定向标准输入,通过printf将内容输出到文件描述符1指代的文件。

Linux I/O重定向 dup dup2 系统调用相关推荐

  1. linux dup2实现重定向,dup/dup2输出重定向

    函数原型:#include int dup(int oldfd); int dup2(int oldfd,int newfd); dup用来复制oldfd所指的文件描述符.但复制成功时返回最小的尚未被 ...

  2. Linux:dup/dup2 文件描述符重定向函数(有图有代码有真相!!!)

    一.dup/dup2 有时我们希望把标准输入重定向到一个文件,或者把标准输出重定向到一个网络连接.系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号 ...

  3. 进程间通信管道进阶篇:linux下dup/dup2函数的用法

    由于利用管道实现进程间通信,是通过创建两个文件描述符,但是描述符的初始化是通过随机的,就是从可用的文件描述符中取出,并将可用的文件描述符与file对象相关联,如果我们需要将管道的两头与其他的流相关时, ...

  4. linux dup跨进程使用,linux下dup/dup2函数的用法

    系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号).dup2可以让用户指定返回的文件描述符的值,如果需要,则首先接近newfd的值,他通常用来重新 ...

  5. Linux应用编程之dup函数和dup2函数

    在 Linux 系统中,open 返回得到的文件描述符 fd 可以进行复制,复制成功之后可以得到一个新文件描述符,使用新的文件描述符和旧的文件描述符都可以对文件进行 IO 操作,复制得到的文件描述符和 ...

  6. dup/dup2函数的用法

    系统调用dup和dup2能够复制文件描述符.dup返回新的文件文件描述符(没有用的文件描述符最小的编号).dup2可以让用户指定返回的文件描述符的值,如果需要,则首先接近newfd的值,他通常用来重新 ...

  7. dup/dup2的用法及详解(转)

    相信大部分在Unix/Linux下编程的程序员手头上都有<Unix环境高级编程>(APUE)这本超级经典巨著.作者在该书中讲解dup/dup2之前曾经讲过"文件共享", ...

  8. 如何在Linux平台下重定向running进程

    如何在Linux平台下重定向running进程 一.简介   本文通过一个具体的示例,介绍在Linux平台下重定向running(运行中)进程的几种方法.借助此方法,用户能够将进行打印重定向到需要的位 ...

  9. Linux内核之旅/张凯捷——系统调用分析(2)

    在<系统调用分析(1)>Linux内核之旅/张凯捷--系统调用分析(1)中,首先介绍了系统调用的概念,并对早期通过软中断(int 80)来进行系统调用的相关过程进行了分析,最后分析和介绍了 ...

  10. Linux详解 --- 重定向及其原理

    文章目录 重定向 重定向的原理 输出重定向 追加重定向 输入重定向 重定向函数dup2 重定向 重定向有三种类型:输出重定向.追加重定向.输入重定向 问题:重定向的效果是什么?   输出重定向:将本应 ...

最新文章

  1. Matlab数据的可视化 -- 极坐标图及其与直角坐标图的转换
  2. docker配置容器运行jar包
  3. python 的案例实战_python案例实战之一
  4. Raft -【go一致性算法】
  5. NLP简报(Issue#7)
  6. 程序猿的执业修养(七)——不要卖弄,多思慎言
  7. SimpleFs文件系统初步二(测试用的块设备构建)
  8. Simulink汽车动力学仿真
  9. 都有哪些较好用的项目管理软件?
  10. LODOP设计打印模板
  11. 焊接好的CH340G芯片不工作
  12. matlab gnuplot,Gnuplot 64位版(gnuplot颜色渲染)V5.2.3 安装版
  13. 抖音支付唤起支付失败,报错10003
  14. ROS学习笔记之导航(仿真)
  15. 帝国CMS灵动标签e:loop
  16. 【C++】绘制一个登录窗口
  17. Java程序员面试技巧:这样面试通过率增加90%
  18. 十年,又回到原点,也许是个新的起点
  19. 分享几款常用的嵌入式软件开发工具
  20. 基于Android的网络菜谱app,基于Android平台的菜谱实现

热门文章

  1. 黑马程序员--java基础复习之网络编程
  2. DAEMON 中的 SPTD 和 发生sptd.sys 错误的处理办法~
  3. pages.json tabBar[‘list‘][2][‘pagePath‘] “pages/contact/contect“ 需在 pages 数组中
  4. CodeForces - 950C Zebras 模拟变脑洞的天秀代码
  5. 对接payjs的个人支付之微信扫码支付接口
  6. 医院管理源码 排队叫号管理源码
  7. 排队叫号python编程_排队叫号系统源程序
  8. 每天多抽出一分钟看书,让你的什么更加精彩。1111节当当购书码
  9. 地理信息系统和计算机系统的区别,GIS与其他信息系统的区别
  10. 插件化框架集成-360插件框架DroidPlug