dup,dup2函數【轉】

來源:互聯網
上載者:User

標籤:

轉自:http://eriol.iteye.com/blog/1180624

轉自:http://www.cnblogs.com/jht/archive/2006/04/04/366086.html

 

dup和dup2也是兩個非常有用的調用,它們的作用都是用來複製一個檔案的描述符。它們經常用來重新導向進程的stdin、stdout和stderr。這兩個函數的原形如下:

 

C代碼  
  1. #include <unistd.h>  
  2. int dup( int oldfd );  
  3. int dup2( int oldfd, int targetfd );  

 

 

dup()函數

 

利用函數dup,我們可以複製一個描述符。傳給該函數一個既有的描述符,它就會返回一個新的描述符,這個新的描述符是傳給它的描述符的拷貝。這意味著,這兩個描述符共用同一個資料結構。例如,如果我們對一個檔案描述符執行lseek操作,得到的第一個檔案的位置和第二個是一樣的。下面是用來說明dup函數使用方法的程式碼片段:

 

C代碼  
  1. int fd1, fd2;  
  2. ...  
  3. fd2 = dup( fd1 );  

 

    需要注意的是,我們可以在調用fork之前建立一個描述符,這與調用dup建立描述符的效果是一樣的,子進程也同樣會收到一個複製出來的描述符。 

 

 

dup2()函數

 

    dup2函數跟dup函數相似,但dup2函數允許調用者規定一個有效描述符和目標描述符的id。dup2函數成功返回時,目標描述符(dup2函數的第二個參數)將變成源描述符(dup2函數的第一個參數)的複製品,換句話說,兩個檔案描述符現在都指向同一個檔案,並且是函數第一個參數指向的檔案。下面我們用一段代碼加以說明:

 

C代碼  
  1. int oldfd;  
  2. oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 );  
  3. dup2( oldfd, 1 );  
  4. close( oldfd );  

 

    在本例中,我們開啟了一個新檔案,稱為“app_log”,並收到一個檔案描述符,該描述符叫做fd1。我們調用dup2函數,參數為oldfd和1,這會導致用我們新開啟的檔案描述符替換掉由1代表的檔案描述符(即stdout,因為標準輸出檔案的id為1)。任何寫到stdout的東西,現在都將改為寫入名為“app_log”的檔案中。需要注意的是,dup2函數在複製了oldfd之後,會立即將其關閉,但不會關掉新近開啟的檔案描述符,因為檔案描述符1現在也指向它。 

 

 

例子

 

下面我們介紹一個更加深入的範例程式碼。回憶一下命令列管道,我們可以將ls –l命令的標準輸出作為標準輸入串連到wc –l命令。接下來,我們就用一個C程式來加以說明這個過程的實現。代碼如下所示。 

 

C代碼  
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4.   
  5. int main()  
  6. {  
  7.     int pfds[2];  
  8.   
  9.     if ( pipe(pfds) == 0 ) {  
  10.   
  11.     if ( fork() == 0 ) {  
  12.   
  13.         close(1);  
  14.         dup2( pfds[1], 1 );  
  15.         close( pfds[0] );  
  16.         execlp( "ls", "ls", "-l", NULL );  
  17.   
  18.     } else {  
  19.   
  20.         close(0);  
  21.         dup2( pfds[0], 0 );  
  22.         close( pfds[1] );  
  23.         execlp( "wc", "wc", "-l", NULL );  
  24.   
  25.     }  
  26.   
  27.     return 0;  
  28. }  

 

    在範例程式碼中,首先在第9行代碼中建立一個管道,然後將應用程式分成兩個進程:一個子進程(第13–16行)和一個父進程(第20–23行)。接下來,在子進程中首先關閉stdout描述符(第13行),然後提供了ls –l命令功能,不過它不是寫到stdout(第13行),而是寫到我們建立的管道的輸出端,這是通過dup2函數來完成重新導向的。在第14行,使用dup2 函數把stdout重新導向到管道(pfds[1])。之後,馬上關掉管道的輸入端。然後,使用execlp函數把子進程的映像替換為命令ls –l的進程映像,一旦該命令執行,它的任何輸出都將發給管道的輸入端。 

 

    現在來研究一下管道的接收端。從代碼中可以看出,管道的接收端是由父進程來擔當的。首先關閉stdin描述符(第20行),因為我們不會從機器的鍵盤等標準裝置檔案來接收資料的輸入,而是從其它程式的輸出中接收資料。然後,再一次用到dup2函數(第21行),讓管道的輸入端作為輸入,這是通過讓檔案描述符0(即常規的stdin)重新導向到pfds[0]實現的。關閉管道的stdout端(pfds[1]),因為在這裡用不到它。最後,使用 execlp函數把父進程的映像替換為命令wc -l的進程映像,命令wc -l把管道的內容作為它的輸入(第23行)。

 

這兩個函數的功能是輸出的重新導向
      定義這兩個函數的標頭檔是unistd.h,有興趣的可以自己看看這個標頭檔包含的內容
      
      要提的是這個標頭檔同時定義了下面三個常量

    • STDERR_FILENO = 2 標準錯誤輸出
    • STDIN_FILENO  = 0 標準輸入
    • STDOUT_FILENO  = 1 標準輸出

      兄弟們學習網路編程用0,1,2這些參數的時候也得知道代表的意思

      要說這兩個函數的意思,還是看一段具體的代碼
      

int fd, fd2;  
mode_t fd_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;  
 
void redir_stdout(const char *filename)  
{  
    fd2=dup(STDOUT_FILENO);  
    fd = open(filename, O_WRONLY|O_CREAT, fd_mode);  //開啟檔案操作
    dup2(fd, STDOUT_FILENO);  //把輸出重新導向到fd標識的檔案
    close(fd);  
}  


      fd2=dup(STDOUT_FILENO);說明fd2表示了標準輸出
      如果我們想把剛剛定向到fd的輸出,再定向回標準輸出,我們可以用下面的代碼實現:

void resume_stdout()  //恢複輸出,把標準輸出定向到fd2,fd2代表的是標準輸出
{  
    dup2(fd2, STDOUT_FILENO);   
    close(fd2);  

 

dup,dup2函數【轉】

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.