实时更新os.walk文件列表[python]

时间:2017-09-11 17:58:10

标签: python os.walk

我有一个函数,我想枚举目标文件夹中的所有文件和文件夹。当/如果它找到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时,调用者可以就地修改dirnames列表   (可能使用del或切片分配),而walk()只会递归   进入名称保留在dirnames中的子目录;这可以   用来修剪搜索,强加一个特定的访问顺序,甚至   通知walk()有关调用者创建或重命名的目录   在它再次恢复walk()之前。自上而下修改dirnames   False对步行的行为没有影响,因为在自下而上   模式dirnames中的目录是在dirpath本身之前生成的   是生成的。

再次阅读它我看到它只提到了dirnames而不是文件名 - 所以虽然我仍然不明白完成这个的确切方法,但看起来你可能只能操作dirnames到位了。

1 个答案:

答案 0 :(得分:0)

sendAjax = () => {
  //this.props.navigation returns a value and I can navigate to 'Login'

  if(!Regex.test(this.state.email)){
  }else if(this.state.password != this.state.confirmPwd){
    Alert.alert("The passwords don't match!");
  }else{
    const fn = encodeURIComponent(this.state.firstname);
    ...
    const hashDigest = sha256(p);
    const requestBody = `firstname=${fn}...

    //POST
    fetch("http://localhost:3000/users", {
        method: "POST",
        mode: "cors",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        body: requestBody
    }).then(function (res, next) {
        console.log("fetch request ", JSON.stringify(res.ok));
        if(res.ok){
            res.json().then(function (json) {
                if(json.registerstate){
                    Alert.alert('Register success, please login');
                    //Cannot read property 'navigation' of undefined
                    this.props.navigation.navigate('Login')
                }
            });
        }
    })
    .then((res) => {
      Alert.alert("then working");
    })
    ....
  }
}
正如您所发现的那样,

for root, dirs, files in os.walk('d:\\test'): for file in files: #process stuff 是您正在迭代的列表 - you should not modify it。当您files删除在for循环迭代中未到达的文件时,您可以做三件事(我能想到)

  1. 在处理之前检查文件是否存在

    process stuff
  2. 使用try / except来捕获IOError。如果您想进一步限制异常处理,可以查询错误文本"没有这样的文件或目录:' yourfilehere'"在except套件中,如果异常不同,则重新引发异常。

    if fname not in os.listdir(os.getcwd()):
        continue
    
  3. 我猜你可以保留一个单独的列表/集合,其中包含你的进程已删除的所有文件,并在尝试处理之前检查文件是否在其中。

  4. 如果你真的需要,你可以写一个具有你需要的行为的课程。

    fname = 'foo.bar'
    try:
        with open(fname) as f:
            pass
    except IOError as e:
        #print(e, str(e), repr(e))
        if 'No such file' in str(e):
            pass
    else:
        raise
    

    结果

    #Python 2.7 code
    import collections
    class F(collections.deque):
        def __iter__(self):
            return self
        def next(self):
            try:
                return self.pop()
            except IndexError:
                raise StopIteration
    
    a = [1,2,3,4]
    f = F(a)
    for n in f:
        print n
        if n == 3:
            f.remove(2)