目录
dup使用介绍
系统调用接口dup具体内容可以在终端使用指令man -2 dup
查看具体使用:
int dup(int oldfd)用于对fd进行复制,指定新的fd,传入的参数oldfd为需要进行复制的初始fd
调用成功后返回值为复制得到的fd的数值。否则返回-1。
使用dup进行文件描述符复制
使用dup系统调用对fd进行复制时,会返回一个新的文件描述符( 如原来的fd是3,返回的fd值可能为4 )
示例代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int fd1,fd2 = -1;
fd1 = open("a.txt",O_RDWR | O_CREAT | O_TRUNC,0666) ;
if (fd1==-1){
perror("open failed");
}
printf("fd1 = %d\n",fd1);
fd2 = dup(fd1);
printf("fd2 = %d\n",fd2);
close(fd1);
}
实际运行结果;
我们不能使用dup系统调用来指定复制后得到的fd为多少,复制后的fd是由操作系统内部自动分配的,分配的原则遵守fd分配的原则(即除去系统占用的fd0,1,2外,最小未被使用的fd。)
dup返回的fd和原来的oldfd都指向oldfd打开的那个动态文件,操作这两个fd实际操作的都是oldfd打开的文件。实际上构成了文件共享。
使用dup的缺陷分析
dup并不能指定分配的新的文件描述符的数字,dup2系统调用修复了这个缺陷,所以平时项目中实际使用时根据具体情况来决定用dup还是dup2.
系统文件提示符0、1、2这三个fd被标准输入、输出、错误通道占用。实际上我们可以关闭这三个fd。
我们可以close(1)关闭标准输出,关闭后,printf函数需要输出的内容就不再输出到标准输出中了。
我们可以使用系统调用接口dup重新分配得到1这个fd,这时候就把oldfd打开的这个文件和1这个标准输出通道相互绑定起来。这即为标准输出的重定位。
重定位如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int fd1,fd2 = -1;
//打开文件
fd1 = open("a.txt",O_RDWR | O_TRUNC);
if (fd1==-1){
perror("open failed");
}
printf("fd1 = %d\n",fd1);
close(1);//将系统fd标准输出关闭
fd2 = dup(fd1);
printf("fd2 = %d\n",fd2);
close(fd1);
}
运行后结果为:
因为进行了重定向,所以第二个printf的输出结果应该保存在了a.txt文档中,而不能标准输出在控制台。
我们查看a.txt的内容进行验证:
因此,我们可以使用close和dup接口配合使用。进行文件的重定位。
dup2使用介绍
dup2和dup的作用一样,都是复制一个新的文件描述符。但是dup2允许用户
指定新的文件描述符的数字。
使用方法看man手册函数原型:
dup2共享文件交叉写入测试
dup2复制的文件描述符,和原来的文件描述符虽然数值不一样,但是指向同一个打开的文件
假设交叉写入时,使用dup2写文件的结果是接续写。
我们通过代码检验;
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int fd1,fd2 = -1;
//打开文件
fd1 = open("a.txt",O_RDWR | O_TRUNC |O_CREAT,0644);
if (fd1==-1){
perror("open failed");
}
printf("fd1 = %d\n",fd1);
fd2 = dup2(fd1,7);
while (1){
sleep(1);
write(fd1,"aa",2);
printf("[write in aa]\n");
sleep(2);
write(fd2,"bb",2);
printf("[write in bb]\n");
}
close(fd1);
}
编译运行该程序
查看写入文件
至此可知,交叉写入文件时,文件的最终结果是接续写。
命令行重定位(使用重定位符号‘>’)
linux中的shell命令执行后,打印结果都是默认进入stdout的(本质上是因为这些命令,例如ls、pwd等,都是调用printf进行打印),所以我们可以在linux的终端shell中直接看到命令执行的结果。
能否想办法把ls、pwd等命令的输出给重定位到一个文件中(譬如2.txt)去?
实际上linux终端支持一-个重定位的符号>很简单可以做到这点。
如下为示例,将系统调用dup手册内容重定位写入a.txt文件中:
查看a.txt内容:
发现成功地用重定位'>'将shell命令行的结果写入指定文件中。
这里提到重定位‘>’是因为其原理和本节内容相关,使用到系统调用接口dup。因为>的实现原理,就是利用open+close+dup, 先调用open接口打开一个需要将结果写入的文件,然后调用close关闭stdout(标准输出),最后调用dup接口将用于系统输出的文件标识符1和需要写入的文件关联起来(复制oldfd)即可。