【发布时间】:2020-02-07 11:41:52
【问题描述】:
考虑以下用于清理目录的 python 函数:
def cleanDir(path):
shutil.rmtree(path)
os.mkdir(path)
在 Windows 上(实际在 Windows7 和 Windows10 上使用 python 2.7.10 和 3.4.4 进行了测试),同时使用 Windows Explorer 导航到相应目录时(或仅在左侧树窗格中导航到父文件夹时) ),可能会引发以下异常:
Traceback (most recent call last):
...
File "cleanDir.py", line ..., in cleanDir
os.mkdir(path)
PermissionError: [WinError 5] Access is denied: 'testFolder'
此问题已在此issue 中报告。但是没有进一步分析,使用睡眠的给定解决方案并不令人满意。根据 Eryk 的 cmets,在当前的 python 版本(即 python 3.8)中,同样的行为也可以预期。
注意shutil.rmtree 无异常返回。但是尝试立即再次创建目录可能会失败。 (重试大多数情况下是成功的,请参阅下面的完整测试代码。)请注意,您需要在 Windows 资源管理器的左右两侧的测试文件夹中单击以强制解决问题。
问题似乎出在 Windows 文件系统 API 函数中(而不是在 Python os 模块中):当 Windows 资源管理器在相应文件夹上有句柄时,删除的文件夹似乎不会立即“转发”到所有函数.
import os, shutil
import time
def populateFolder(path):
if os.path.exists(path):
with open(os.path.join(path,'somefile.txt'), 'w') as f:
f.write('test')
#subfolderpath = os.path.join(path,'subfolder')
#os.mkdir(subfolderpath)
#with open(os.path.join(subfolderpath,'anotherfile.txt'), 'w') as f2:
# f2.write('test')
def cleanDir(path):
shutil.rmtree(path)
os.mkdir(path)
def cleanDir_safe(path):
shutil.rmtree(path)
try:
#time.sleep(0.005) # makes first try of os.mkdir successful
os.mkdir(path)
except Exception as e:
print('os.mkdir failed: %s' % e)
time.sleep(0.01)
os.mkdir(path)
assert os.path.exists(path)
FOLDER_PATH = 'testFolder'
if os.path.exists(FOLDER_PATH):
cleanDir(FOLDER_PATH)
else:
os.mkdir(FOLDER_PATH)
loopCnt = 0
while True:
populateFolder(FOLDER_PATH)
#cleanDir(FOLDER_PATH)
cleanDir_safe(FOLDER_PATH)
time.sleep(0.01)
loopCnt += 1
if loopCnt % 100 == 0:
print(loopCnt)
【问题讨论】:
-
@ErykSun 使用 python 2.7.10 和 python 3.4.4 测试
-
@ErykSun 我们已经明确观察到这种行为:
shutil.rmtree成功后,os.path.exists(path)(“读取访问”)始终为False。如果在shutil.rmtree之后“快速”调用os.mkdir(path)(“写访问”)可能会失败。使用给定的测试代码,这应该很容易重现。 -
@ErykSun“已删除但仍链接的目录”:这种暂时不一致的状态不是 Windows 文件系统 API 中的错误吗?
-
@ErykSun 所以从 python 3.5.8 开始(例如也在 python 3.6 中)在
shutil.rmdir(path)之后直接调用os.mkdir(path)是安全的吗? -
@ErykSun 带有
FindFirstFileW的示例代码会很棒,因为我们无法立即将代码库升级到 python 3.5+