Python中删除只读目录

43

shutil.rmtree不会在Windows上删除只读文件。是否有Python等效的"rm -rf"? 为什么这么麻烦?


为什么这个如此痛苦?也许还没有人花五分钟去在 http://bugs.python.org/ 上报告一个 bug... 你可以成为第一个!只是说一下。 - Jason Orendorff
1
我知道我来晚了,但我刚刚提交了http://bugs.python.org/issue22040。 - Paul Moore
7个回答

72

shutil.rmtree可以传入一个错误处理函数,当删除文件时出现问题时会调用该函数。您可以使用它来强制删除有问题的文件。

灵感来源于http://mail.python.org/pipermail/tutor/2006-June/047551.htmlhttp://techarttiki.blogspot.com/2008/08/read-only-windows-files-with-python.html

import os
import stat
import shutil

def remove_readonly(func, path, excinfo):
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(top, onerror=remove_readonly)

(我还没有测试过那段代码,但它应该足以让您开始)


1
这对我非常有效,甚至在Python单元测试中也是如此。谢谢! - Lëmön
5
一行代码:shutil.rmtree('mypath',onerror = lambda func, path, _: (os.chmod(path, stat.S_IWRITE), func(path))) - Basj
如果目录不存在,这个方法如何处理,即在自身包含ignore_errors=True - Ali_Sh

4
如果您从PyWin32导入win32api,您可以使用以下代码:
win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL)

使文件不再是只读文件。

4
另一种方法是将Windows上的rmtree定义为:
rmtree = lambda path: subprocess.check_call(['cmd', '/c', 'rd', '/s', '/q', path])

3
这个问题预计会在Python 3.5(目前 - 2015年6月 - 仍在开发中)发布时得到解决,文档将提供有关此的提示。
您可以在这里找到错误报告。而这个是相应的修改集。
请参阅从Python 3.5文档中新增加的示例:
import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

3
ActiveState 网站上有一条评论指出:

shutil.rmtree 有其局限性。尽管在许多情况下可以使用 shutil.rmtree(),但在某些情况下它无法正常工作。例如,在 Windows 下标记为只读的文件无法通过 shutil.rmtree() 删除。

通过从 PyWin32 导入 win32api 和 win32con 模块,并向 rmgeneric() 函数添加类似于 "win32api.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL" 的代码行,即可克服这个障碍。我使用了这种方法来修复 Subversion 1.4 的 hot-backup.py 脚本,使其在 Windows 下运行良好。感谢您提供的这份配方。

我不使用 Windows,因此无法验证其是否有效。


2

1

在调用rmtree()时,我遇到了Python 3.7的这个问题,并通过在退出TemporaryDirectory()上下文管理器之前显式修复权限来解决它。有关详细信息,请参见akaihola/darker#453。以下是实现的副本:

import os
import sys
from pathlib import Path
from typing import Union

WINDOWS = sys.platform.startswith("win")

def fix_py37_win_tempdir_permissions(dirpath: Union[str, Path]) -> None:
    """Work around a `tempfile` clean-up issue on Windows with Python 3.7

    Call this before exiting a ``with TemporaryDirectory():`` block or in teardown for
    a Pytest fixture which creates a temporary directory.

    See discussion in https://github.com/akaihola/darker/pull/393
    Solution borrowed from https://github.com/python/cpython/pull/10320

    :param dirpath: The root path of the temporary directory

    """
    if not WINDOWS or sys.version_info >= (3, 8):
        return
    for root, dirs, files in os.walk(dirpath):
        for name in dirs + files:
            path = os.path.join(root, name)
            try:
                os.chflags(path, 0)  # type: ignore[attr-defined]
            except AttributeError:
                pass
            os.chmod(path, 0o700)

以下是如何在 Pytest 单元测试中或使用 tempfile 创建临时目录的方法:

import pytest

from my_utils import fix_py37_win_tempdir_permissions

@pytest.fixture
def myfixture(tmp_path):
    # setup code here
    yield tmp_path
    fix_py37_win_tempdir_permissions(tmp_path)


def myfunc():
    with TemporaryDirectory() as tmpdir:
        # work on the temporary directory here
        fix_py37_win_tempdir_permissions(tmp_path)

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