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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章