使用 stat 检测文件是不是存在(慢?)

Posted

技术标签:

【中文标题】使用 stat 检测文件是不是存在(慢?)【英文标题】:using stat to detect whether a file exists (slow?)使用 stat 检测文件是否存在(慢?) 【发布时间】:2010-07-29 13:25:32 【问题描述】:

我正在使用如下代码在继续之前检查文件是否已创建,问题是文件在被 stat 检测到之前就已在文件浏览器中显示...这样做有问题吗这个?

//... do something

struct stat buf;

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

//... do something else

或者有没有更好的方法来检查文件是否存在?

【问题讨论】:

什么文件浏览器?什么是写文件?您确定该文件没有以稍微不同的名称写入然后在最后一刻重命名吗? 我正在使用 konqueror,但 dolphin 也会在 stat 之前通知我。该文件是由我编写的应用程序编写的,所以我知道应该写什么以及在哪里写。此外,该文件是一个空文件,我正在编写只是为了表明进程已完成。 你指的这个延迟时间是多久?它是微秒级还是分钟级? stat() 应该没有理由在文件确实存在时无法指示文件存在。我怀疑这里还发生了一些你还没有意识到的事情。 这就是我的想法。它在 10 秒到一分钟左右的范围内。它当然值得注意。 您的程序是在同一台机器上运行,还是使用 NFS 或其他文件服务器协议?您确定您的 while 循环实际上正在运行吗? (让它在每次睡眠时打印"not yet" 或其他内容。) 【参考方案1】:

使用inotify,您可以安排内核在文件系统发生更改(例如文件创建)时通知您。这很可能是您的文件浏览器用来快速了解文件的原因。

【讨论】:

【参考方案2】:

“stat”系统调用正在收集有关文件的不同信息,例如指向该文件的多个硬链接或其“inode”编号。您可能想查看“访问”系统调用,仅通过在“模式”中指定“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);

【讨论】:

一个问题,sleep(1) 有这么大的问题吗...几秒钟的延迟不是问题,这是我对添加 sleep 调用的最大期望。 不,如果我们在这里谈论 10 到 60 秒的延迟,消除睡眠只是追求卓越而不是解决问题。 Greg Hewgill 就类似 NFS 的复制和不同的机器提出了正确的问题。这些是最可能的原因。此外,还有一个“waitpid”系统调用,您可以使用它来等待进程完成,而不是创建/轮询文件。 这也有一个竞争条件,即在 notify OR 访问函数调用之后不能保证文件存在。仅在通话时。事实上,应该避免测试文件是否存在。如果您无法访问它或在使用它时丢失它,您应该假设该文件存在并处理该案例。示例 1:文件存在但您无权访问。示例 2:文件“消失”,因为挂载消失 (NFS)。【参考方案3】:

您的代码将每秒检查文件是否存在。您可以改用inotify 来获取事件。

【讨论】:

以上是关于使用 stat 检测文件是不是存在(慢?)的主要内容,如果未能解决你的问题,请参考以下文章

如何检测项目文件夹中是不是存在文件?

如何检测iOS中是不是存在大文件?

检测文件是不是存在[重复]

php基础:变量检测

c#中如何检测文件路径是不是存在

为啥HDFS写入速度如此之慢