【问题标题】:Python open() fails on Windows when another process is opening the file当另一个进程打开文件时,Python open() 在 Windows 上失败
【发布时间】:2018-02-08 18:14:05
【问题描述】:

我在 Windows 中看到一些关于文件句柄的令人惊讶的行为。

我有两个进程都试图获取同一个底层文件的只读文件句柄。

进程 A(Go 二进制文件)打开该文件的只读文件句柄,然后使用它来获取文件的排他锁。

进程 B(一个 Python 二进制文件)然后尝试在 same 文件上打开一个只读文件句柄,这会导致以下 IOError

IOError: [Errno 13] Permission denied: 'C:\\path\\to\\file.txt'

当进程 A 不在时,进程 B 打开文件没有问题。

据我所知,Windows 上的两个进程都持有同一个文件的只读文件描述符没有问题,而且我还没有找到任何文档表明其中一个持有独占锁的进程会更改.

有谁知道导致 Python open() 调用失败的原因是什么?

(如果有帮助,我使用的 Go 文件锁定实现是 this one。)

【问题讨论】:

  • 你甚至说进程 A 用它来创建一个独占锁。
  • 我认为我的困惑源于这样一个事实,即在 Unix 系统上,打开和锁定文件是完全正交的概念。进程 B 可以打开一个由进程 A 独占锁定的文件。根据 tocode 的回答(我现在已经接受),在 Windows 上似乎不是这种情况。

标签: python windows file-locking


【解决方案1】:

正如this answer 中所建议的那样,如果进程没有访问文件的权限或文件被另一个进程锁定,open() 将抛出 IOError

要验证它是第二个而不是第一个,您可以使用os.access() 来检查该进程是否具有访问该文件的权限。

例如:

if not os.access(FILE_PATH, os.R_OK):
  print "Failure opening file: No read access for %s" % FILE_PATH
  return

try:                                                                                                                                                      
  fd = open(FILE_PATH)
  print "Success opening file"
except IOError:
  print "Failure opening file: Another process holds lock on %s" % FILE_PATH

对于 Unix 系统上的 flock,打开和锁定文件是不同的概念。但是,Windows 系统上的 LOCK_FILE_EX 实际上会阻止其他进程打开文件的该部分以进行读取或写入访问 (source)。

【讨论】:

  • os.access 在这种情况下在 Windows 上毫无意义。它只检查与F_OKW_OK 相关的文件属性(只读属性)。正如所写,它与检查文件权限无关。最好通过使用所需访问权限直接调用CreateFile 来检查。如果它因访问被拒绝 (5) 而失败,则您知道您没有被允许进行所需的访问。如果它因共享违规而失败 (32),您知道您通常是被允许的;但是,该文件当前处于打开状态,但没有共享所需的读取、写入或删除权限。
  • Windows 文件锁定绝不会阻止打开文件。文件锁定应用于文件的区域,并且仅在尝试读取或写入锁定区域时才被检查。多次打开文件的访问受到单独的 I/O 共享机制的保护,该机制适用于为读取/执行、写入/附加或删除访问而打开的文件。请参阅creating and opening files,了解共享模式的工作原理。
  • eryksun,我不确定您的解释是否能解释我所看到的行为。一个 golang 程序以读取权限打开文件,一个 python 程序以读取权限打开文件,我希望它们都能够保持并发句柄。然而,情况似乎并非如此。 (golang 调用看起来像 file, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0666),Python 调用看起来像 file = open(path)。)
  • @candrews,我可以告诉你标准 Python 2 open 调用 Microsoft C fopen / _wfopen,最终调用 CreateFile 并设置共享模式以允许读写共享.顺便说一句,我不知道golang如何实现OpenFile。如果它没有将共享模式设置为允许读取共享,那么 Python 中的open 将失败并出现权限错误。它实际上是共享冲突 (winerror 32) 而不是访问被拒绝 (winerror 5),但是 Microsoft C 通过将数千个 Windows 错误代码映射到大约 50 个 POSIX 错误代码,例如EACCES (13),让我们的生活变得困难。
  • @candrews,我查看了您正在使用的锁定库。它的 Windows 实现不是基于实际的文件锁定(即LockFileExUnlockFileEx)来锁定文件的区域。相反,如果share 为假,它会使用共享模式作为“锁定”调用CreateFile,否则允许读写共享(但不能删除)。在这种情况下,唯一可能的“解锁”是关闭文件句柄。
猜你喜欢
  • 1970-01-01
  • 2021-07-17
  • 2020-09-12
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-04
  • 1970-01-01
相关资源
最近更新 更多