您可能在 Mac OSX 上,并且您的目录至少部分在非 Mac 文件系统上(即不是 HFS+)。在这些上,Mac 文件系统驱动程序会自动创建以._ 为前缀的二进制伴随文件,以记录所谓的扩展属性(在https://apple.stackexchange.com/questions/14980/why-are-dot-underscore-files-created-and-how-can-i-avoid-them 中进行了解释,但也如下所示)。
rmtree 在不支持os.scandir 中的文件描述符的系统上(如 Mac OSX)现在不安全地创建条目列表,然后将它们一一解除链接(创建已知的竞争条件:https://github.com/python/cpython/blob/908fd691f96403a3c30d85c17dd74ed1f26a60fd/Lib/shutil.py#L592-L621)。不幸的是,每次都有两种不同的行为使这种情况成立:
- 原始文件始终列在扩展属性之一之前,并且
- 取消链接原始文件 (
test.txt) 时,同时删除元文件 (._test.txt)。
因此,在轮到你的时候会丢失扩展属性文件并抛出你正在经历的FileNotFoundError。
我认为这个错误最好由cpython#14064 解决,它的目的是通常忽略rmtree 中的FileNotFoundErrors。
缓解
同时,您可以使用onerror 忽略这些元文件上的取消链接错误:
def ignore_extended_attributes(func, filename, exc_info):
is_meta_file = os.path.basename(filename).startswith("._")
if not (func is os.unlink and is_meta_file):
raise
shutil.rmtree(path_dir, onerror=ignore_extended_attributes)
Mac 扩展属性案例展示
为了说明您可以创建一个小的 ExFAT 磁盘映像并使用命令将其挂载到 /Volumes/Untitled
hdiutil create -size 5m -fs exfat test.dmg
hdiutil attach test.dmg # mounts at /Volumes/Untitled
cd /Volumes/Untitled
mkdir test # create a directory to remove
cd test
touch test.txt
open test.txt # open the test.txt file in the standard editor
只需在标准文本编辑器中打开文件,就会创建一个扩展属性文件._test.txt,并在其中记录上次访问时间:
/Volumes/Untitled/test $ ls -a
. .. ._test.txt test.txt
/Volumes/Untitled/test $ xattr test.txt
com.apple.lastuseddate#PS
问题是自动取消链接原始文件也会取消链接伴随文件。
/Volumes/Untitled/test $ rm test.txt
/Volumes/Untitled/test $ ls -a
. ..