APUE编程:15---文件I/O之(文件描述符复制函数:dup()、dup2())
原创
©著作权归作者所有:来自51CTO博客作者董哥的黑板报的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、函数介绍
#include <unistd.h>
int dup(int fd);
int dup2(int fd, int fd2);
dup()
-
功能:复制fd所指的文件描述符,返回一个新的文件描述符
- 自己不能指定新的文件描述符,系统自己分配一个最小的可用的文件描述符
-
fd参数:一个已存在并打开的文件描述符
-
返回值:
dup2()
-
功能:复制fd所指的文件描述符,返回一个新的文件描述符
-
参数:
- fd:一个已存在并打开的文件描述符
- fd2:自己传入的,指定新的文件描述符
-
使用方法:
- 如果fd2已经打开,则先将其关闭
- 如果fd等于fd2,那么dup2函数不执行任何操作,dup2函数返回fd2,而不关闭它
- 否则fd2的FD_CLOEXEC文件描述符标志就被清除,这样fd2在进程调用exec时是打开状态
数据结构剖析
- 这两个函数返回的新文件描述符与参数fd共享同一个文件表项
- 假设我们现在执行下面的代码:
int newfd = dup(1);
- 当此函数开始执行时,假定下一个可用的描述符是3 (这是非常有可能的,因为 0,1和2由shell打开)。因为两个描述符指向同一文件表项,所以它们共享同一文件状态标志 (读、写、添写等) 以及同一当前文件位移量
- 两个函数创建的文件描述符并不继承原文件描述符的属性,比如close-on-exec和non-blocking等。每个文件描述符都有它自己的一套文件描述符标志。正如我们将在下一节中说明的那样, 新描述符的执行时关闭( 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
三、演示案例
- 先打开一个描述符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使用同一个文件表。文件偏移量等都是相同的
四、演示案例