如何在C++中检查文件是否被其他应用程序打开?

12

我知道在C++中有is_open()函数,但我想要一个程序来检查文件是否已被另一个应用程序打开。是否有使用标准库的方法可以实现?

编辑 - 在答案中澄清这是针对Linux应用程序。

10个回答

5

标准库不仅没有这个功能,通常情况下也无法实现。在Linux上,您可以检查/proc/*/fd - 但有可能您的程序没有权限查看其他用户的进程(例如,在Ubuntu中默认是如此)。


“一般情况下不可能”并不完全正确,可以参考fuser程序。 - Waslap
我认为你不能在没有sudo的情况下使用fuser来知道另一个进程是否正在访问该文件,对吗?@Waslap - Shiva Shahrokhi

4
不,标准库没有这样的功能。

3
以下代码可能有效。
int main(int argc, char ** argv)
{
    int fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    if (fcntl(fd, F_SETLEASE, F_WRLCK) && EAGAIN == errno) {
        puts("file has been opened");
    }
    else {
        fcntl(fd, F_SETLEASE, F_UNLCK);
        puts("file has not been opened");
    }

    close(fd);
    return 0;
}

在我的情况下,即使文件已经打开,这个例子总是返回“文件未被打开”的结果。ls -al /proc/21862/fd/47 l-wx------ 1 user user 64 1월 29 17:12 /proc/21862/fd/47 -> /home/user/data/201802201020.mp4。(Ubuntu) - uthline

3
如果您控制另一个进程(有源代码),最好的方法是在两个进程中都使用咨询锁定。该锁定在POSIX中定义,并且可在各种操作系统上移植。
在Linux中,您可以使用实用程序lsof查看其他进程打开的文件。
这仅限于您拥有权限的内容-您必须以特权用户的身份进行检查,否则您只会获得由执行检查的用户打开的文件的结果。
我只知道命令行实用程序,不知道您可以直接从C代码使用的任何系统调用。
在Linux中,还可以为给定的文件系统启用强制锁定(mount -o mand),并在文件上设置特殊标志(chmod g-x,g + s)。然后,当您的进程尝试获取写锁时,如果另一个进程打开了该文件,则会失败。这几乎从未使用过,但如果您完全控制所涉及的系统,则可能是一种选择。

1
有一次我试图查看lsof源代码,想看看他们是如何做到的,结果我的脑袋差点炸了。lsof的源代码就像一个疯狂和黑魔法的网络。 - Tyler McHenry
2
我建议使用fuser而不是lsof。解析结果会更简单。 - AFoglia

2
也许您可以尝试获取完整的写锁定?如果有其他人正在读取或写入,它将失败。
fopen("myfile.txt", "r+")

如果它不是跨平台的而是Win32,那么您可以请求更细粒度的锁定集合。

请参见此处并查看dwShareMode,值为0以及其他参数。


完全依赖于操作系统。 - anon

0

看到你已经标记了linux -> 这里有一条命令行和API已添加到Linux内核中,可以实现这一点:inotify

这里是man页面。


0

0

+1 我一直在寻找一个能够像 handle.exe 一样工作的应用程序。感谢 ZombieSheep。 - Kei

0

正如@Neil Butterworth所说,标准库并没有提供此功能。

在Unix中,您可以使用fcntl来使用文件锁。

您可以编写一个包装器函数来检查文件是否被其他人打开,并在没有锁定的情况下对其进行锁定。您还应该为关闭编写一个包装器函数,在文件关闭时释放该锁定。


锁定仅仅是一种建议性的措施,因此它只能告诉你是否有其他人锁定了该文件。 - ephemient

-1

在Windows中,这个小而“不太光彩”的技巧会起作用(前提是文件存在且你拥有正确的权限)

  if (  0 != rename("c:/foo.txt", "c:/foo.txt")  ) {
     printf("already opened\n");
  }

这个程序很可能也能在Linux上运行。


我可以很容易地想象未来有人在操作系统中添加“修复”功能,从而破坏了这个技巧。 - Brian
3
在Linux中,你可以在文件打开的同时重命名它。文件是按照inode(索引节点)来跟踪的,而不是按照名称。你甚至可以删除该文件,具有该文件的进程将继续读取它而不会出现错误。 - jmanning2k
1
在资源管理器中,您还可以重命名由于被锁定而无法删除的文件。当您想要复制文件到现有文件上,但无法覆盖已锁定的文件时,这非常有用。 - Kevin Doyon
非常非常糟糕 :) 当我们没有重命名权限时,我们会得到有关已打开文件的错误信息 :P - Znik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接