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打开)。因为两个描述符指向同一文件表项,所以它们共享同一文件状态标志 (读、写、添写等) 以及同一当前文件位移量
- 每个文件描述符都有它自己的一套文件描述符标志。正如我们将在下一节中说明的那样, 新描述符的执行时关闭( 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;
}
- fd与dup_fd使用同一个文件表。文件偏移量等都是相同的