【问题标题】:Python: Dissagreement between os.isfile() and os.listdir()Python:os.isfile() 和 os.listdir() 之间的分歧
【发布时间】:2014-11-15 18:30:22
【问题描述】:

我想用 os.remove() 删除一个文件,然后对目录中剩余的文件做一些工作。但是,我发现 os.listdir() 在超过一定大小时仍然包含已删除的文件。 “好的”,我想,“os.remove() 只是异步工作。没什么大不了的,我将使用 os.path.isfile() 检查文件是否已被完全删除”。结果证明这行不通。以下代码举例说明了这个问题:

import os

with open("test/test.txt", 'w') as file:
    for _ in range(100):
        file.write("spam")

print os.path.isfile("test/test.txt")
print os.listdir("test/")

os.remove("test/test.txt")

print os.path.isfile("test/test.txt")
print os.listdir("test/")

这将创建一个 400 字节的小文件。输出如预期:

True
['test.txt']
False
[]

但是当写入的“垃圾邮件”数量增加到 10 000 000(一个 40Mb 的文件)时,会出现以下输出:

True
['test.txt']
False
['test.txt']

所以,isfile() 很清楚文件已被删除,但 listdir() 还没有发现。

是否有一种更可靠的方法来检查文件是否存在,并且始终与以下 listdir() 调用一致?

在 Windows 7 上使用 Python 2.7 进行测试,这是否重要。

----编辑

我无意立即打开任何文件;我想在列表框中显示目录中剩余的所有文件。我觉得打开每个文件来检查它是否有不必要的地方,但也许这就是 Python 的做事方式?

【问题讨论】:

  • Python 的通用座右铭是EAFP;只是盲目地做任何你想做的事情并捕捉错误。在处理文件时更是如此。如果你想分割IOErrors,你也可以查看errno
  • 我注意到,如果我以交互方式运行它,那么它对两个文件的工作方式相同,正如预期的那样。所以,我认为这与时机有关。可能在脚本中运行时,在 isfile 和 listdir 运行之前 remove 操作还没有完成,各自对状态的反应不同。
  • 我不知道这有多大帮助,但这段代码的行为就像你在我的 Mac 上所期望的那样。因此,它很可能专门针对 Windows 文件交互。
  • 我在 windows 7 / python 2.7.2.5 上试过这个,没有看到你的问题。第二个os.listdir 没有列出任何文件。我认为这是一个严重错误。我在本地驱动器和 Linux samba 服务器的 CIFS 共享上尝试了它。您使用的是什么媒体?谁能重现这个?!

标签: python python-2.7


【解决方案1】:

在 Windows 中,如果您删除由其他东西打开的文件(使用 FILE_SHARE_DELETE),则在关闭之前不会真正删除它。相反,它的条目仍然存在,标记为“待删除”(并且您无法打开它并出现模糊错误)。我认为这是造成差异的原因 - os.path.isfile 认为它存在但不再是“常规文件”。

如果是这种情况,os.path.exists 应该返回 True

在这种情况下,一种可能的解决方案是列出所有文件(还有一个额外的好处是过滤掉目录等),即

print [f for f in os.listdir(path) if os.path.isfile(os.path.join(path,f))]

当然,当您在查询条目时发生变化时,这会为竞争条件提供机会。在这种情况下,除非您的操作系统支持系统调用事务,否则这是不可避免的。

【讨论】:

  • 使用Process Monitor (ProcMon),我刚刚确认了当ProcMon 在感兴趣的目录上报告DELETE PENDINGos.path.exists()os.path.isdir() 都返回False 的情况。
【解决方案2】:

你没有提到你想对这些文件做什么,但在 Python 中,请求宽恕比请求权限更容易,所以尝试任何方法,如果出现问题就失败。

import os
import glob
import errno

def process(file_handle):
    for line in file_handle:
        return line

for fn in glob.iglob('*.py'):
    try:
        with open(fn) as f:
            print(process(f))
    except IOError as e:
        if e.errno == errno.ENOENT:
            # file doesn't exist, ignore
            pass
        else:
            # some other error we don't want to suppress
            raise

【讨论】:

    猜你喜欢
    • 2018-06-10
    • 2018-05-10
    • 2015-04-07
    • 2023-04-06
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    相关资源
    最近更新 更多