在 Python 中等待 Windows 文件 I/O 完成

Posted

技术标签:

【中文标题】在 Python 中等待 Windows 文件 I/O 完成【英文标题】:Wait for Windows file I/O to complete in Python 【发布时间】:2014-03-09 00:05:30 【问题描述】:

我有一组系统测试,它们会启动一些进程、创建文件等,然后将它们全部关闭并删除文件。

我在清理时遇到两个间歇性错误:

在由其中一个进程创建的日志文件上:

    os.remove(log_path)
WindowsError: [Error 32] The process cannot access the file because it is being used by another process: <path_to_file>

尝试使用shutil.rmtree 删除输出目录时:

File "C:\Python27\lib\shutil.py", line 254, in rmtree
    os.rmdir(path)
WindowsError: [Error 145] The directory is not empty: 'C:\\TestTarget\\xxx'

如果我在整理之前插入 2 秒延迟,这两个错误都会消失,所以我认为问题在于 Windows 释放文件所需的时间。显然我想避免延迟测试,有没有办法等到文件系统赶上?

【问题讨论】:

你可以在一个循环中插入一个try 块并循环直到它成功......这行得通吗? 这是一个合理的权宜之计,谢谢。如果有的话,我想要一个更清洁的解决方案。 我认为只要进程在关闭时正确关闭文件,应该可以立即删除。您可能会寻找问题的真正原因。 :-) 我也遇到过类似的问题。我认为这要么是防病毒软件的问题,要么是 NTFS 中的错误。根据我的经验,它通常会很快解决,因此最简单的解决方法是检测故障,短暂延迟(可能 10 毫秒),然后循环重试。 这里有同样的问题。我正在删除一个目录 shutil.rmtree(),然后使用 os.rename() 将另一个目录重命名为相同的目录,并收到错误“当该文件已存在时无法创建文件”。在我看来有点荒谬,我正在尝试使用 python 作为跨平台的 shell/batch 替换,而且我绝对从未在 shell 或批处理脚本中看到过这种类型的问题。 【参考方案1】:

我遇到了类似的问题,我花了几个月的时间寻找合适的解决方案,但一无所获。对我来说,这个问题只发生在使用 python2.7 在 Windows 上运行我的脚本时。在python3上大部分时间都没有问题。在 GNU/Linux 上,我可以在没有这种肮脏解决方案的情况下使用文件操作。

我最终将这个函数用于 Windows 的任何文件操作:try_fail_wait_repeat(见下文),你应该做类似的事情。您也可以将睡眠设置为不同的值。

import sys
import shutil
import time
import os

IS_WINDOWS = (sys.platform == "win32")


if IS_WINDOWS:
    maximum_number_of_tries = 40
    def move_folder(src, dst): 
        return try_fail_wait_repeat(maximum_number_of_tries, _move_dir, src, dst)
    def read_file(path): 
        return try_fail_wait_repeat(maximum_number_of_tries, _read_file, path)
else:
    def move_folder(src, dst):
        return shutil.move(src, dst)
    
    def read_file(path):
        return _read_file(path)


def _read_file(file_path):
    with open(file_path, "rb") as f_in:
        data = f_in.read().decode("ISO-8859-1")
    return data


def try_fail_wait_repeat(maximum_number_of_tries, func, *args):
    """A dirty solution for a dirty bug in windows python2"""
    i = 0
    while True:
        try:
            res = func(*list(args))
            return res
        except WindowsError as e:
            i += 1
            time.sleep(0.5)
            if i > maximum_number_of_tries:
                print("Too much trying to run ()".format(func, args))
                raise e

【讨论】:

【参考方案2】:

你使用的函数只删除空目录

尝试:

import shutil
shutil.rmtree('/folder_path')

另外,请尝试在关闭进程之前添加睡眠间隔。

【讨论】:

我发现 rmtree 调用 os.rmdir(path) 并且仍然给出相同的错误。 ```clear_directory 中的 clear_directory() shutil.rmtree(download_dir) 文件“C:\python27_x64\lib\shutil.py”,第 247 行,在 rmtree rmtree(fullname, ignore_errors, onerror) 文件“C:\python27_x64\lib\ shutil.py",第 256 行,在 rmtree onerror(os.rmdir, path, sys.exc_info()) 文件 "C:\python27_x64\lib\shutil.py",第 254 行,在 rmtree os.rmdir(path) WindowsError : [错误 145] 目录不为空: 'D:\\downloads\\test' '''

以上是关于在 Python 中等待 Windows 文件 I/O 完成的主要内容,如果未能解决你的问题,请参考以下文章

异步 I/O 多路复用(套接字和线程间)

如何在批处理脚本中等待? [复制]

Windows system 在python文件操作时的路径表示方法

网络编程——I/O复用

python代码如何判断windows文件是不是为只读?

Windows XP线程的调度策略