Python显式设置权限后仍无法删除Windows文件问题排查
问题根因
- 权限修改逻辑完全无效:你仅对
resources根目录调用了os.chmod,没有递归处理目录下的所有文件;且Python的os.chmod在Windows平台仅支持设置stat.S_IWRITE对应的只读标记,你传入的其余POSIX权限位(读、执行、用户组权限等)在NTFS系统下会被直接忽略,这就是你递归调用chmod也看不到权限变化的根本原因。 - 缺少短暂占用重试逻辑:你确认进程释放了dll句柄,但刚写入磁盘的dll会被Windows Defender等杀毒软件做实时扫描、系统文件缓存也会短暂持有句柄,这个占用窗口通常只有几百毫秒。你手动删除时Windows资源管理器自带隐式重试,等占用释放后就删掉了,但unittest的
tearDownClass是用例执行完立刻触发删除,刚好撞上占用窗口,直接抛错。 - 默认删除逻辑无容错:Python 3.9的
shutil.rmtree默认采用_rmtree_unsafe实现,遇到只读文件、短暂占用的文件会直接抛出错误,没有任何重试、权限修正逻辑。
修复方案
- 给
shutil.rmtree传入onerror回调,遇到删除错误时先移除目标文件/目录的只读属性,再重试操作。 - 给删除流程加显式重试,遇到权限错误时等待几百毫秒后再次尝试,覆盖系统/杀软短暂占用的场景。
- 优先使用标准库的
tempfile.TemporaryDirectory管理临时解压目录,它已经封装了Windows平台下的所有清理兼容逻辑,不需要自己手写路径维护、权限处理代码。
修正后的清理代码如下:
import os import stat import time import shutil def _handle_remove_error(func, path, exc_info): # 移除目标的只读属性 os.chmod(path, stat.S_IWRITE) # 等待短暂占用释放 time.sleep(0.2) # 重试删除操作 func(path) class Check(): def __init__(self, file_path, unzip_dir=None): self.file_path = file_path self.unzip_dir = unzip_dir def terminate(self): if self.unzip_dir is None: return # 最多重试3次,覆盖短暂占用场景 for _ in range(3): try: shutil.rmtree(self.unzip_dir, onerror=_handle_remove_error) return except PermissionError: time.sleep(0.5) # 重试全部失败再抛出错误 shutil.rmtree(self.unzip_dir, ignore_errors=False)
如果改用标准库临时目录管理,代码可以更简洁,不需要自己写清理逻辑:
import tempfile import zipfile # 临时目录会在with块退出时自动清理,自带Windows平台兼容逻辑 with tempfile.TemporaryDirectory() as unzip_dir: # 解压压缩包到临时目录 with zipfile.ZipFile(self.file_path, 'r') as archive: archive.extractall(unzip_dir) # 所有依赖解压文件的测试逻辑都写在with块内即可
内容的提问来源于stack exchange,提问作者doa4321
相关产品推荐
相关产品推荐

