【问题标题】:How to check if a file has been opened by another application in C++?如何检查文件是否已被 C++ 中的另一个应用程序打开?
【发布时间】:2010-11-06 02:57:07
【问题描述】:

我知道,C++ 中有 is_open() 函数,但我希望一个程序检查一个文件是否未被另一个应用程序打开。有没有办法使用标准库来做到这一点?

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

【问题讨论】:

    标签: c++ linux file-io process


    【解决方案1】:

    不仅标准库不具备这种功能,甚至一般情况下也不可能。您可以(在 linux 上)检查 /proc/*/fd — 但您的程序可能没有权限在其他用户的进程上执行此操作(例如,这是 Ubuntu 中的默认设置)。

    【讨论】:

    • '一般情况下甚至不可能'并不完全正确,请参阅 fuser 程序
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      如果您控制另一个进程(有源代码),最好的计划是在两个进程中都使用咨询锁。这种锁定是在 POSIX 中定义的,并且可以跨操作系统移植。

      在 Linux 中,您可以使用实用程序 lsof 查看其他进程打开了哪些文件。

      这仅限于您拥有的权限 - 您必须以特权用户的身份进行检查,否则您只会获得与执行检查的用户相同的用户打开的文件的结果。

      我只知道命令行实用程序,不知道任何可以直接从 C 代码中使用的系统调用。

      在 Linux 中,还可以为给定的文件系统打开 mandatory locking(mount -o mand),并在文件上设置特殊标志(chmod g-x,g+s)。然后,当您的进程尝试获取写锁时,如果另一个进程打开了文件,它将失败。这几乎从未使用过,但如果您完全控制有问题的系统,它可能是一种选择。

      【讨论】:

      • 我曾经尝试查看 lsof 源代码,看看他们是如何做到的,我的脑袋几乎要爆炸了。 lsof 的源头是一张疯狂和黑魔法的网络。
      • 我建议使用 fuser 而不是 lsof。解析结果会简单得多。
      【解决方案4】:

      以下代码可能有效。

      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 -&gt; /home/user/data/201802201020.mp4。 (Ubuntu)
      【解决方案5】:

      也许你可以尝试获得一个完整的写锁?如果其他人将其打开以供阅读或写作,它将失败。

      fopen("myfile.txt", "r+")
      

      如果不是跨平台的,是Win32的,那么你可以请求更细粒度的锁。

      here 并查看dwShareMode,值为0,以及其他参数。

      【讨论】:

      • 完全依赖于操作系统。
      【解决方案6】:

      不。除非其他应用程序使用咨询锁。

      http://docs.sun.com/app/docs/doc/816-0213/6m6ne37v5?a=view

      【讨论】:

        【解决方案7】:

        如果不是本地人,您可以拨打Sysinternals' handle.exe 作为最后的手段...

        【讨论】:

        • +1 我一直在寻找一个与handle.exe 完全一样的应用程序。谢谢 ZombieSheep。
        【解决方案8】:

        正如@Neil Butterworth 所说,标准库没有。

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

        您可以为您的 open 函数编写一个包装器,如果文件未被其他人打开,它会检查文件是否存在锁(如果不存在则锁)。您还应该为关闭编写一个包装器,以释放文件关闭时的锁定。

        【讨论】:

        • 锁定纯粹是建议性的,所以这只会告诉你是否有其他人聚集了文件。
        【解决方案9】:

        看到您已经标记了 linux -> 还有一个命令行和 API 已添加到 Linux 内核并执行此操作:inotify

        这是man 页面。

        【讨论】:

          【解决方案10】:

          在 Windows 中,这个 肮脏 的小技巧会起作用(如果文件存在并且您拥有正确的权限)

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

          它可能也适用于 Linux。

          【讨论】:

          • 我可以很容易地想象将来有人会在操作系统中添加一个“修复”来打破这个技巧。
          • 在 linux 中,您可以在文件打开时重命名文件。文件由 inode 跟踪,而不是名称。你甚至可以删除文件,打开它的进程会继续读取它而不会出错。
          • 在资源管理器中,您还可以重命名因锁定而无法删除的文件。当您想在现有文件上复制文件并且无法覆盖锁定的文件时非常有用。
          • 真的很脏 :) 当我们无权重命名此文件时,我们会收到有关打开文件的错误信息:P
          猜你喜欢
          • 2014-11-22
          • 2010-12-29
          • 1970-01-01
          • 2012-03-09
          • 1970-01-01
          • 2023-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多