文件描述符复制

系统调用函数dupdup2可以实现文件描述符的复制,经常用来重定向进程的stdin(0),stdout(1),stderr(2)。

dup返回新的文件描述符没有使用的文件描述符的自动获取还没有分配的最小编号)。这个新的描述符是旧文件描述符的拷贝。这意味着两个描述符共享同一个数据结构。

dup2允许调用者用一个有效描述符(oldfd)和目标描述符(newfd),函数成功返回时,目标描述符将变成旧描述符的复制品,此时两个文件描述符现在都指向同一个文件,并且是函数第一个参数(也就是oldfd)指向的文件。返回值和目标描述符一样
原型为:

#include <unistd.h>    //头文件包含
int dup(int oldfd);
int dup2(int oldfd, int newfd);   //成功返回新的描述符,失败返回-1

文件描述符的复制是指用另外一个文件描述符指向同一个打开的文件,它完全不同于直接给文件描述符变量赋值,例如:
        char szBuf[32];
     int fd=open(“./a.txt”,O_RDONLY);
     int fd2=fd;                                                 //类似于C语言的指针赋值,当释放掉一个得时候,另一个已经不能操作了
     close(fd);                                                  //导致文件立即关闭
     printf(“read:%d ”,read(fd2,szBuf,sizeof(szBuf)-1));        //读取失败
     close(fd2);                                                 //无意义
在此情况下,两个文件描述符变量的值相同,指向同一个打开的文件,但是内核的文件打开引用计数还是为1,所以close(fd)或者close(fd2)都会导致文件立即关闭掉。

所以必须要用dup来赋值

int fd1=dup(fd);  文件的引用计数+1

//dup.c
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<strings.h>
int main(int argc,char **argv)
{
        int fd1 = open(argv[1],O_RDWR);
        char buf[32];
        read(fd1,buf,10);
        printf("fd1=%d  buf=%s ",fd1,buf);
        int fd2 = fd1;    //变量赋值方式,内核文件打开引用计数还是为1
        int fd3 = dup(fd1);    //内核文件打开引用计数+1
        printf("fd2=%d ",fd2);
        printf("fd3=%d ",fd3);
        close(fd1);
        printf("--------------------------- ");
        bzero(buf,sizeof(buf));
        read(fd2,buf,10);
        printf("fd2=%d  buf=%s ",fd2,buf);  //fd1关闭,导致fd2不能操作文件
        close(fd2);
        bzero(buf,sizeof(buf));
        read(fd3,buf,10);
        printf("fd3=%d  buf=%s ",fd3,buf);  //fd3不是fd1的赋值,fd1关闭不影响fd3的操作
//文件指针被fd1偏移了10,fd3不能从开头读取数据了。
        close(fd3);
        return 0;
}



**如果close(fd) 改成 close(1) //关闭标准输出,那么结果buf将不会输出来

//这就是关闭了标准输出后的结果 

读标准输入 read(0,buf,sizeof(buf));   
//可以用来代替scanf


 
//dup2.c
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<strings.h>
int main(int argc,char **argv)
{
        int fda = open(argv[1],O_RDONLY);
        int fdb = open(argv[2],O_RDONLY);
        printf("before dup fda=%d fdb=%d ",fda,fdb);
        int fdaa = dup(fda);
        printf("dup fda=%d fdaa=%d ",fda,fdaa);
        int fdup2b = dup2(fdb,fdaa);   //fdaa从指向argv[1]变成指向argv[2],fup2b也指向argv[2];
        printf("dup2 fdb=%d fdaa=%d fdup2b=%d ",fdb,fdaa,fdup2b);
        char buf[32];
        read(fda,buf,sizeof(buf));
        printf("fda read buf=%s ",buf);
        bzero(buf,sizeof(buf));
        read(fdb,buf,sizeof(buf));
        printf("fdb read buf=%s ",buf);
        lseek(fda,0,SEEK_SET);
        lseek(fdb,0,SEEK_SET);
        bzero(buf,sizeof(buf));
        read(fdaa,buf,sizeof(buf));
        printf("fdaa read buf=%s ",buf);
        lseek(fdaa,0,SEEK_SET);
        bzero(buf,sizeof(buf));
        read(fdup2b,buf,sizeof(buf));
        printf("fdup2b read buf=%s ",buf);
        return 0;
}


//dup2使用场合
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
        int fd = open("a.txt", O_WRONLY | O_CREAT);
        if(fd == -1)
        {
                perror("open error");
                exit(-1);
        }
        printf(" ");  /* 必不可少 */
        close(1);   //关闭标准输出;
        int fd2 = dup(fd);   //复制描述符fd,fda会选区未分配的最小描述符给fd2,fd2=1;
        close(fd);
        printf("hello world ");  //printf用调用stdout(1)描述符进行屏幕标准输出的,现在1变成文件a.txt文件的描述符了,所以就直接输出到文件中
        close(fd2);
        return 0;
}
该程序首先打开了一个文件,返回一个文件描述符,因为默认的就打开了0,1,2表示标准输入,标准输出,标准错误输出。而用close(1);则表示关闭标准输出,此时这个文件描述符就空着了。后面又用dup,此时dup(fd);则会复制一个文件描述符到当前未打开的最小描述符,此时这个描述符为1.后面关闭fd自身,然后在用标准输出的时候,发现标准输出重定向到你指定的文件了。那么printf所输出的内容也就直接输出到文件了。

dup2(int fdold,int fdnew)也是进行描述符的复制,只不过采用此种复制,新的描述符由用户用参数fdnew显示指定,而不是象dup一样由内核帮你选定(内核选定的是随机的)。对于dup2,如果fdnew已经指向一个已经打开的文件,内核会首先关闭掉fdnew所指向的原来的文件。此时再针对于fdnew文件描述符操作的文件,则采用的是fdold的文件描述符。如果成功dup2的返回值于fdnew相同,否则为-1.



原文地址:https://www.cnblogs.com/meihao1203/p/8441021.html