2010-07-29 35 views
6

我正在使用下面的代碼來檢查文件是否在繼續之前被創建,事情是文件在文件瀏覽器中出現之前很久檢測到stat ...這樣做有問題嗎?使用stat來檢測文件是否存在(很慢?)

//... do something 

struct stat buf; 

while(stat("myfile.txt", &buf)) 
    sleep(1); 

//... do something else 

或者有更好的方法來檢查文件是否存在?

+0

什麼文件瀏覽器?什麼是寫文件?你確定這個文件沒有被寫成一個稍微不同的名字,然後在最後一刻被重命名嗎? – 2010-07-29 13:28:14

+0

我使用的是konqueror,但海豚也比stat更早通知我。該文件正在寫我所寫的一個應用程序,所以我知道應該寫什麼和在哪裏。此外,該文件是我寫的空文件,只是爲了表示進程已完成。 – 2010-07-29 13:50:28

+0

你所指的這段延遲時間有多長?它是微秒級還是分鐘級?應該沒有理由說明爲什麼'stat()'應該在它確實存在時指示文件存在。我懷疑你還沒有意識到還有其他事情在發生。 – 2010-07-29 13:53:55

回答

3

「stat」系統調用正在收集有關文件的不同信息,例如,指向它的多個硬鏈接或其「inode」編號。您可能需要查看「access」系統調用,您只能通過在「mode」中指定「F_OK」標誌來執行存在檢查。

但是,您的代碼存在一些小問題。它會在每次檢查尚不存在的文件時讓進程休眠一秒。爲了避免這種情況,您必須按照Jerry Coffin的建議使用inotify API,以便在您等待的文件存在時通過內核獲得通知。請記住,如果文件已經存在,inotify不會通知您,所以實際上您需要同時使用「access」和「inotify」以避免在創建文件之後開始監視文件時的競爭狀況。

沒有更好或更快的方法來檢查文件是否存在。如果您的文件瀏覽器仍然顯示文件稍快於此程序檢測到它,那麼Greg Hewgill關於重命名的想法可能正在發生。

這裏是一個C++代碼示例設置了一個inotify的手錶,如果文件已經存在,檢查和否則爲它等待:

#include <cstdio> 
#include <cstring> 
#include <string> 

#include <unistd.h> 
#include <sys/inotify.h> 

int 
main() 
{ 
    const std::string directory = "/tmp"; 
    const std::string filename = "test.txt"; 
    const std::string fullpath = directory + "/" + filename; 

    int fd = inotify_init(); 
    int watch = inotify_add_watch (fd, directory.c_str(), 
            IN_MODIFY | IN_CREATE | IN_MOVED_TO); 

    if (access (fullpath.c_str(), F_OK) == 0) 
    { 
     printf ("File %s exists.\n", fullpath.c_str()); 
     return 0; 
    } 

    char buf [1024 * (sizeof (inotify_event) + 16)]; 
    ssize_t length; 

    bool isCreated = false; 

    while (!isCreated) 
    { 
     length = read (fd, buf, sizeof (buf)); 
     if (length < 0) 
      break; 
     inotify_event *event; 
     for (size_t i = 0; i < static_cast<size_t> (length); 
      i += sizeof (inotify_event) + event->len) 
     { 
      event = reinterpret_cast<inotify_event *> (&buf[i]); 
      if (event->len > 0 && filename == event->name) 
      { 
       printf ("The file %s was created.\n", event->name); 
       isCreated = true; 
       break; 
      } 
     } 
    } 

    inotify_rm_watch (fd, watch); 
    close (fd); 
} 
+0

有一個問題,睡眠(1)是一個如此大的問題......幾秒鐘的延遲不是問題,這是我期望添加睡眠呼叫的最多。 – 2010-07-29 14:57:05

+0

不,消除睡眠只是追求卓越,而不是解決問題,如果我們在這裏談論10到60秒的延遲。 Greg Hewgill就NFS類複製和不同機器問題提出正確的問題。這些事情是最可能的原因。 此外,還有一個「waitpid」系統調用,您可以使用它來等待進程完成而不是創建/輪詢文件。 – 2010-07-29 15:13:04

+0

這也有競爭條件的事實,即在通知或訪問函數調用後沒有保證文件存在的事實。只在通話時。實際上,應該避免測試是否存在文件。你應該假設文件存在,並處理這種情況,如果你無法訪問它或在使用它時丟失它。示例1:文件存在但您無權訪問。示例2:由於掛載消失(NFS),文件「消失」。 – Rahly 2016-09-15 17:13:44

4

使用inotify,您可以安排內核在發生文件系統更改(如文件創建)時通知您。這很可能是您的文件瀏覽器用來快速瞭解文件的原因。

1

你的代碼會檢查文件是否每秒都在那裏。您可以使用inotify來取代事件。