Linux(编程-文件):03---文件描述符复制函数(dup、dup2)

dup()、dup2()

#include <unistd.h>
int dup(int fd);
int dup2(int fd, int fd2);
//两函数的返回:若成功为新的文件描述符,若出错为- 1
//参数:1.一个以存在的文件描述符
  •  dup():不能指定新的文件描述符,系统自己分配一个最小的可用的文件描述符
  • dup2():可以用参数2指定新的文件描述符。如果fd2已经打开,则先将其关闭。如果fd等于fd2,则dup2返回fd2,而不关闭它。否则fd2的FD_CLOEXEC文件描述符标志就被清除,这样fd2在进程调用exec时是打开状态
  • 重点:这两个函数返回的新文件描述符与参数fd共享同一个文件表项
  • 当此函数开始执行时,假定下一个可用的描述符是 3 (这是非常有可能的,因为 0,1和2由shell打开)。因为两个描述符指向同一文件表项,所以它们共享同一文件状态标志 (读、写、添写等) 以及同一当前文件位移量

Linux(编程-文件):03---文件描述符复制函数(dup、dup2)

  • 每个文件描述符都有它自己的一套文件描述符标志。正如我们将在下一节中说明的那样, 新描述符的执行时关闭( close-on-exec )文件描述符标志总是由dup函数清除 

复制一个描述符的另一种方法是使用fcntl函数:

  • 方法一:调用dup(fd);等效于fcntl(fd, F_DUPFD, 0);
  • 方法二:调用dup2(fd, fd2);等效于close(fd2);fcntl(fd, F_DUPFD, fd2);

在最后一种情况下,dup2并不完全等同于close加上fcntl。它们之间的区别是:

  • dup2是一个原子操作,而close及fcntl则包括两个函数调用。有可能在close和fcntl之间调用了信号捕获函数,它可能修改文件描述符。如果不同的线程改变了文件描述符的话也会出现相同的问题
  • 在dup2和fcntl之间有某些不同的errno
dup2系统调用起源于V7,然后传播至所有BSD版本。而复制文件描述符的
fcntl方法则首先由系统III使用,系统 V继续采用。 SVR3 . 2选用了dup2函数,
4 . 2BSD则选用了fcntl函数及F_DUPFD功能。POSIX . 1要求d u p 2及fcntl的F_DUPFD
功能二者兼有。

演示案例

  • 先打开一个描述符fd读取dup.txt5个字节,然后用dup复制一个描述符dup_fd读取5个字节。然后再使用原来的fd再读取5个字节,观察结果
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char *argv[])
{
    int fp;
    if((fp=open("dup.txt",O_RDONLY))==-1){
        perror("open file error");
        exit(EXIT_FAILURE);
    }

    char buf[5];

    memset(buf,'\0',sizeof(buf));
    if((read(fp,buf,5))<=0){
        perror("read file error");
        exit(EXIT_FAILURE);
    }
    printf("now buf data is %s\n",buf);

    int dup_fp=dup(fp);
    memset(buf,'\0',sizeof(buf));
    if((read(dup_fp,buf,5))<=0){
        perror("read file error");
        exit(EXIT_FAILURE);
    }
    printf("now buf data is %s\n",buf);

    memset(buf,'\0',sizeof(buf));
    if((read(fp,buf,5))<=0){
        perror("read file error");
        exit(EXIT_FAILURE);
    }
    printf("now buf data is %s\n",buf);

    close(fp);
    return 0;
}


Linux(编程-文件):03---文件描述符复制函数(dup、dup2)

Linux(编程-文件):03---文件描述符复制函数(dup、dup2)

  • fd与dup_fd使用同一个文件表。文件偏移量等都是相同的