Linux高级I/O函数 dup, dup2, dup3
2022/5/1 7:13:44
本文主要是介绍Linux高级I/O函数 dup, dup2, dup3,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- dup()
- 示例1
- dup2()
- 示例2
- dup3()
- 示例3
- 参考
dup()
如何把标志输入(stdin)重定向到一个文件,或者把标志输出(stdout)重定向到一个网络连接(sockfd)?
可以用系统调用dup或dup2。
#include <unistd.h> int dup(int oldfd); int dup2(int oldfd, int newfd);
dup() 创建一个新fd,和原有fd指向相同的文件、管道或网络连接。dup()返回的文件描述符总是取系统当前可用最小整数值。
示例1
将fd2重定向到fd1。然后,从键盘接收输入,并将内容写入fd2所指文件
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main() { int fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, 0774); if (fd < 0) { perror("open error"); exit(-1); } int fd2 = dup(fd); if (fd2 < 0) { perror("dup error"); exit(-1); } printf("fd = %d, fd2 = %d\n", fd, fd2); // 通常fd = 3, fd2 = 4, 因为0,1,2分别为标准输入、标准输出、标准错误 char buf[128]; ssize_t n; /* 从键盘接收输入并写入fd2所指文件 */ while (( n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { if (write(fd2, buf, static_cast<size_t>(n)) < 0) { printf("Write error!\n"); exit(-1); } } return 0; }
dup2()
dup2和dup类似,区别在于:
- dup2可以用参数newfd指定新文件描述符的值。
- 如果newfd已经被使用,则系统会将newfd所指文件关闭;如果newfd等于oldfd,则直接返回newfd,而不关闭newfd所指文件。
- dup2复制的文件描述符与原来的文件描述符共享各种文件状态,共享所有的锁定、读写位置、各种权限及flags等,但不包括close-on-exec。
成功调用,则返回新创建的文件描述符;失败返回-1,错误保存到errno。
dup2(oldfd, newfd)结果等价于
close(oldfd); int fd = fcntl(oldfd, F_DUPFD, newfd);
示例2
在dup基础上,做1个小改动:将dup2的newfd指定为fileno(stderr),即值2。可以看到,fd2重定向到了原来stderr所指文件描述符2,而原来的stderr(标准错误)将关闭,而不再能输出错误信息。
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main() { int fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, 0774); if (fd < 0) { perror("open error"); exit(-1); } int fd2 = dup2(fd, fileno(stderr)); // 2 if (fd2 < 0) { perror("dup error"); exit(-1); } printf("fd = %d, fd2 = %d\n", fd, fd2); // fd = 3, fd = 2 fprintf(stderr, "test stderr\n"); char buf[128]; ssize_t n; /* 从键盘接收输入并写入fd2所指文件 */ while (( n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { if (write(fd2, buf, static_cast<size_t>(n)) < 0) { printf("Write error!\n"); exit(-1); } } return 0; }
dup3()
还有一个系统调用dup3,类似于dup2,区别在于:
- 调用者可以强制为新创建的文件描述符指定close-on-exec标志(open搭配O_CLOEXEC,fcntl搭配FD_CLOEXEC)
- 如果oldfd等于newfd,调用失败,报错EINVAL。
#define _GNU_SOURCE /* See feature_test_macros(7) */ #include <fcntl.h> /* Obtain O_* constant definitions */ #include <unistd.h> int dup3(int oldfd, int newfd, int flags);
示例3
在示例1基础上做下改动:判断fd添加O_CLOEXEC后的选项值,然后清除。对比单独为fd添加FD_CLOEXEC选项,和由dup3指定O_CLOEXEC选项,得到的文件描述符的选项差异。
可以看到,dup3指定O_CLOEXEC选项,跟fcntl指定O_CLOEXEC选项的效果是一样的。
int main() { int fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, 0774); if (fd < 0) { perror("open error"); exit(-1); } /* 获得fd的初始flags, 然后添加FD_CLOEXEC选项, 最后清除FD_CLOEXEC选项 */ int flags0 = fcntl(fd, F_GETFD); printf("primary flags of fd is %d\n", flags0); fcntl(fd, F_SETFD, flags0 | FD_CLOEXEC); int flags1 = fcntl(fd, F_GETFD); printf("After adding FD_CLOEXEC, flags of fd is %d\n", flags1); flags1 = fcntl(fd, F_SETFD, flags0); printf("Restore FD_CLOEXEC(cleared), flags of fd is %d\n", flags1); int fd2 = dup3(fd, fileno(stderr), O_CLOEXEC); // 2 if (fd2 < 0) { perror("dup error"); exit(-1); } printf("fd = %d, fd2 = %d\n", fd, fd2); // fd = 3, fd = 2 flags1 = fcntl(fd2, F_GETFD); printf("flags of fd2 is %d\n", flags1); char buf[128]; ssize_t n; /* 从键盘接收输入并写入fd2所指文件 */ while (( n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { if (write(fd2, buf, static_cast<size_t>(n)) < 0) { printf("Write error!\n"); exit(-1); } } return 0; }
参考
https://blog.csdn.net/tiandc/article/details/81489447
这篇关于Linux高级I/O函数 dup, dup2, dup3的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南
- 2024-08-21【Linux】分区向左扩容的方法