dup 与 dup2

来源:互联网 发布:java得到当前项目路径 编辑:程序博客网 时间:2024/06/10 13:30

1. 文件描述符在内核中数据结构

 一个进程在此存在期间,会有一些文件被打开,从而会返回一些文件描述符,从shell

中运行一个进程,默认会有3个文件描述符存在(0、1、2),

0与进程的标准输入相关联,

1与进程的标准输出相关联,

2与进程的标准错误输出相关联,

一个进程当前有哪些打开的文件描述符可以通过/proc/进程ID/fd目录查看。

 下图可以清楚的说明问题:

  进程表项
————————————————

   fd标志 文件指针
      _____________________
fd 0:|________|____________|————> 文件表
fd 1:|________|____________|
fd 2:|________|____________|
fd 3:|________|____________|
       |     …….         |
       |_____________________|

                图1
       
文件表中包含:文件状态标志、当前文件偏移量、v节点指针,这些不是本文讨论的

重点,我们只需要知道每个打开的文件描述符(fd标志)在进程表中都有自己的文件表

项,由文件指针指向。

2. dup/dup2函数

APUE和man文档都用一句话简明的说出了这两个函数的作用:复制一个现存的文件描述符。

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

从图1来分析这个过程,当调用dup函数时,内核在进程中创建一个新的文件描述符,此

描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项。

  进程表项
————————————————

   fd标志 文件指针
      _____________________
fd 0:|________|____________|                          ______
fd 1:|________|____________|—————-> |               |
fd 2:|________|____________|                       | 文件表 |
fd 3:|________|____________|—————-> | _____  |
       |     …….         |
       |_____________________|

                图2:调用dup后的示意图

如图2 所示,假如oldfd的值为1, 当前文件描述符的最小值为3, 那么新描述符3指向

描述符1所拥有的文件表项。

dup2和dup的区别就是可以用newfd参数指定新描述符的数值,如果newfd已经打开,则

先将其关闭。如果newfd等于oldfd,则dup2返回newfd, 而不关闭它。dup2函数返回的新

文件描述符同样与参数oldfd共享同一文件表项。

APUE用另外一个种方法说明了这个问题:

实际上,调用dup(oldfd);

等效与
        fcntl(oldfd, F_DUPFD, 0)

而调用dup2(oldfd, newfd);

等效与
        close(oldfd);
        fcntl(oldfd, F_DUPFD, newfd); 

#include <sys/stat.h>#include <string.h>#include <fcntl.h>#include <stdio.h>#include <unistd.h>int main(void){   #define STDOUT 1   //标准输出文件描述符 号   int nul, oldstdout;   char msg[] = "This is a test";   //打开一个文件,操作者具有读写权限 如果文件不存在就创建   nul = open("DUMMY.FIL", O_CREAT | O_RDWR, S_IREAD | S_IWRITE);   /* create a duplicate handle for standard      output */   oldstdout = dup(STDOUT);   /*      redirect standard output to DUMMY.FIL      by duplicating the file handle onto the      file handle for standard output.   */   dup2(nul, STDOUT);   /* close the handle for DUMMY.FIL */   close(nul);   /* will be redirected into DUMMY.FIL */   write(STDOUT, msg, strlen(msg));   /* restore original standard output      handle */   dup2(oldstdout, STDOUT);   /* close duplicate handle for STDOUT */   close(oldstdout);   return 0;}


 

原创粉丝点击