dup 与 dup2

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); 

[cpp]  view plain  copy
  1. #include <sys/stat.h>  
  2. #include <string.h>  
  3. #include <fcntl.h>  
  4. #include <stdio.h>  
  5. #include <unistd.h>  
  6. int main(void)  
  7. {  
  8.    #define STDOUT 1   //标准输出文件描述符 号  
  9.    int nul, oldstdout;  
  10.    char msg[] = "This is a test";  
  11.    //打开一个文件,操作者具有读写权限 如果文件不存在就创建  
  12.    nul = open("DUMMY.FIL", O_CREAT | O_RDWR, S_IREAD | S_IWRITE);  
  13.    /* create a duplicate handle for standard 
  14.       output */  
  15.    oldstdout = dup(STDOUT);  
  16.    /* 
  17.       redirect standard output to DUMMY.FIL 
  18.       by duplicating the file handle onto the 
  19.       file handle for standard output. 
  20.    */  
  21.    dup2(nul, STDOUT);  
  22.    /* close the handle for DUMMY.FIL */  
  23.    close(nul);  
  24.    /* will be redirected into DUMMY.FIL */  
  25.    write(STDOUT, msg, strlen(msg));  
  26.    /* restore original standard output 
  27.       handle */  
  28.    dup2(oldstdout, STDOUT);  
  29.    /* close duplicate handle for STDOUT */  
  30.    close(oldstdout);  
  31.    return 0;  
  32. }  

今天看到dup和dup2系统调用,目前还不是太理解,先写一点简单的应用实例。

dup和dup2用来复制文件描述符。

函数原型:
#include
int dup(int oldfd);
int dup2(int oldfd,int newfd);


       dup用来复制oldfd所指的文件描述符。但复制成功时返回最小的尚未被使用的文件描述符。若有错误则返回-1,错误代码存入errno中。返回的新文件描述符和参数oldfd指向同一个文件,共享所有的锁定,读写指针,和各项权限或标志位。
       dup2可以用参数newfd指定新文件描述符的数值。若newfd已经被程序使用,系统就会将其关闭以释放该文件描述符;若newfd与oldfd相等,dup2将返回newfd,而不关闭他。dup2调用成功返回新的文件描述符,出错则返回-1。

      标准输入(stdin),标准输出(stdout),标准出错信息(stderr)的文件号分别为0,1,2

一个简单的例子:首先在当前目录下存在一个文件mytest2,文件内容为hhhhhhhhhhhh
 
#include 
#include 
#include 
#include
#include 
#include

 int main()
 {
   int oldfd;

   oldfd = open("mytest2",O_RDWR|O_CREAT,0644);
   dup2(oldfd,1);   //复制oldfd到文件描述符1(stdout标准输出)
   close(oldfd);    //关闭文件描述符oldfd
   printf("ddd");  //在标准输出上打印出ddd,这时由于标准输出已经被oldfd文件描述符代替
   return 0;       //打印到标准输出上的内容就全部打印到了文件mytest2中
 }

程序执行结果为文件mytest2中的内容变为:dddhhhhhhhhh

程序实例:文件名为file5.c

#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
 int fd;
 int i;
 if((fd=open("mytest3",O_CREAT|O_RDWR,0644))==-1){
      printf("open file error!");     
      exit(1);
  }

 close(1);  //关闭标准输出
 dup(fd);  // 复制文件描述符fd到1上
 close(fd);

 printf("writ to file\n");
 return 0;    
}

程序运行时结果:
moalong@xiyoulinux-desktop:~/along/code/c/part5$ make file5
cc     file5.c   -o file5
moalong@xiyoulinux-desktop:~/along/code/c/part5$ ./file5
moalong@xiyoulinux-desktop:~/along/code/c/part5$ cat mytest3
writ to file

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值