【发布时间】:2017-09-11 17:58:10
【问题描述】:
我有一个函数,我想枚举目标文件夹中的所有文件和文件夹。当/如果它找到 rar 文件,我希望它提取它们然后删除它们。在多部分存档的情况下,它还将检查并删除剩余的文件(已与第一卷一起提取)。
我在 for 循环中使用 os.listdir,但这种方法的问题是: a)我认为它不会在不为它们编写递归循环的情况下处理子文件夹(我不想这样做,因为递归伤害了我的头)。 b) 因为 for 循环仅在开始时创建项目的字典(?),所以当它循环到已在先前迭代中删除的文件名时,我将无法找到该文件。
似乎 os.walk 对于上面的“a)”可能更好,我迄今为止的研究表明,我应该能够在每次迭代时实时更新 os.walk。但是我不知道该怎么做。
我有这样的东西:
for root, dirs, files in os.walk('d:\\test'):
for file in files:
print 'files (before remove): ', file, files
# This is where I would do some operation that deletes one or more files.
files.remove(file)
print 'files (after remove): ', file, files
但是输出是这样的:
D:\test>d:\Python27\python.exe d:\file.py
files (before remove): Crystal.part01.rar ['Crystal.part01.rar', 'Crystal.part02.rar', 'Crystal.part03.rar', 'Crystal.part04.rar', 'Crystal.part05.rar', 'Crystal.part06.rar']
files (after remove): Crystal.part01.rar ['Crystal.part02.rar', 'Crystal.part03.rar', 'Crystal.part04.rar', 'Crystal.part05.rar', 'Crystal.part06.rar']
files (before remove): Crystal.part03.rar ['Crystal.part02.rar', 'Crystal.part03.rar', 'Crystal.part04.rar', 'Crystal.part05.rar', 'Crystal.part06.rar']
files (after remove): Crystal.part03.rar ['Crystal.part02.rar', 'Crystal.part04.rar', 'Crystal.part05.rar', 'Crystal.part06.rar']
files (before remove): Crystal.part05.rar ['Crystal.part02.rar', 'Crystal.part04.rar', 'Crystal.part05.rar', 'Crystal.part06.rar']
files (after remove): Crystal.part05.rar ['Crystal.part02.rar', 'Crystal.part04.rar', 'Crystal.part06.rar']
我认为这是有道理的...我们可以看到列表正在更新,但是因为我已经卡在(第二个)For 语句中,该语句创建了一个文件列表,它继续尝试循环遍历原始列表现在偏移一的顺序,产生“跳过”效果。
除了让调用循环知道跳过已删除的项目外,如何实现对目录中每个文件的操作?
更新 - 我假设可以做到这一点可能是不正确的。给我这个想法的原因是从 python 文档中截取的:
当topdown为
True时,调用者可以就地修改目录名列表 (可能使用del或切片赋值),而walk()只会递归 进入名称保留在 dirnames 中的子目录;这可以是 用于修剪搜索,强加特定的访问顺序,甚至 通知walk()调用者创建或重命名的目录 在它再次恢复walk()之前。自顶向下时修改目录名False对 walk 的行为没有影响,因为在自下而上 模式 dirnames 中的目录在 dirpath 本身之前生成 已生成。
再次阅读时,我发现它只提到了目录名而不是文件名 - 所以虽然我仍然不明白实现这一点的确切方法,但看起来你可能只能在适当的位置操作目录名。
【问题讨论】:
-
不要从
files中删除任何内容。 -
除了将其作为标准的 os.walk 循环遍历文件外,什么都不做。如果 Crystal.part01.rar(循环中的第一个)的处理还包括删除第 2-5 部分,则脚本将以
The system cannot find the file specified:错误终止。我需要让调用 loop/walk/whatever 知道某些文件已被删除,它不应该尝试处理它们。 -
补充一下,因为你可能会因为简洁而在我头上说话 - 我知道我可以简单地允许脚本在这里出错并捕获异常 - 假设我们应该期望文件是如果我们只是删除它们就丢失了。但是我不确定这是否真的是最佳实践(?),因为我们会期望/继续任何可能过于宽泛的 IOError...
-
如果您想使用结果来修改底层文件系统,您可以循环访问 os 调用,将它们存储在一个列表中,然后在列表上执行您的操作,然后完成。完成修改后,您可以随时再次调用 os.walk。
-
我更新了 OP 以更正/指定我所指的内容。仍然希望看到一个符合我用例的可行代码示例。谢谢