2015-02-09 31 views
7

我试图编写一个Python函数,递归地删除所有空目录。这意味着如果目录“a”仅包含“b”,则应删除“b”,则应删除“a”(因为它现在不包含任何内容)。如果一个目录包含任何内容,它将被跳过。图说:为什么python的os.walk()不能反映删除目录?

top/a/b/ 
top/c/d.txt 
top/c/foo/ 

鉴于此,三个目录“B”,“A”和“富”应该被删除,因为“foo”和“B”现在是空的,而“一”将成为空删除“b”后。

我试图通过os.walkshutil.rmtree来做到这一点。不幸的是,我的代码只是删除了第一层目录,而不是在这个过程中新清空的目录。

我正在使用topdown=false参数os.walkdocumentationos.walk表示“如果topdown为False,则在其所有子目录的三元组(即自下而上生成的目录)之后生成目录的三元组”。这不是我所看到的。

这里是我的代码:

for root, dirs, files in os.walk(".", topdown=False): 
    contents = dirs+files 
    print root,"contains:",contents 
    if len(contents) == 0: 
    print 'Removing "%s"'%root 
    shutil.rmtree(root) 
    else: 
    print 'Not removing "%s". It has:'%root,contents 

如果我上面描述的目录结构,这里就是我得到:

./c/foo contains: [] 
Removing "./c/foo" 
./c contains: ['foo', 'd.txt'] 
Not removing "./c". It has: ['foo', 'd.txt'] 
./a/b contains: [] 
Removing "./a/b" 
./a contains: ['b'] 
Not removing "./a". It has: ['b'] 
. contains: ['c', 'a'] 
Not removing ".". It has: ['c', 'a'] 

需要注意的是,即使我已经删除“B”,“一个“不会被删除,认为它仍然包含”b“。我感到困惑的是,os.walk的文档说它生成“./a”的三元组,在之后生成“b”的三元组。我的输出表明否则。类似的故事“./c”。它表明它仍然具有“foo”,即使我已经将它删除了。

我在做什么错? (我使用Python 2.6.6。)

+0

我不希望操作系统。步行更新每个迭代的'for'循环 – jcfollower 2015-02-09 20:36:56

+0

我想这是关键。文档中的“之前”和“之后”是指'os.walk()'输出结果数组中的顺序,而不是通过'for'循环连续迭代的时间顺序。调用者在'topdown = True'模式下可以修改'dirnames'参数,这让我认为迭代可能会受到影响。 – seanahern 2015-02-09 20:55:42

回答

2

jcfollower的答案是关于您遇到的问题的原因绝对正确的:文件系统总是读自上而下的,即使结果是从os.walk以自下而上的方式产生。这意味着您执行的文件系统修改将不会反映在后面的结果中。

解决这个问题是维护一组被删除的目录,这样就可以筛选出来的子目录父母的名单:

removed = set()            # first new line 
for root, dirs, files in os.walk(".", topdown=False): 
     dirs = [dir for dir in dirs if os.path.join(root, dir) not in removed] # second 
     contents = dirs+files 
     print root,"contains:",contents 
     if len(contents) == 0: 
      print 'Removing "%s"'%root 
      shutil.rmtree(root) 
      removed.add(root)         # third new line 
     else: 
      print 'Not removing "%s". It has:'%root,contents 

有三个新的生产线。首先,在顶部创建一个空的removed设置为包含已删除的目录。第二个将dirs列表替换为不包含已删除集合中的任何子目录的新列表,因为它们在上一步中被删除。最后一行在删除时将当前目录添加到集合中。

+0

这是一个巧妙的把戏!非常聪明。它承认'os.walk()'会给你提供可能被删除失效的信息,并明确修改它返回的信息。 – seanahern 2015-02-10 16:38:28

9

documentation有这个...

无论自上而下的价值,子目录的列表 元组的目录和它之前检索生成子目录 。

+0

这是迄今为止最好的答案。它说''topdown = False'主要是'os.walk()'输出中的数据排序问题,而不是基础文件系统探索的时间顺序。 – seanahern 2015-02-09 21:15:48