【问题标题】:Can I force os.walk to visit directories in alphabetical order?我可以强制 os.walk 按字母顺序访问目录吗?
【发布时间】:2011-07-12 19:37:46
【问题描述】:

我想知道是否可以在 python3 中强制os.walk 按字母顺序访问目录。例如,这是一个目录和一些将遍历该目录的代码:

ryan:~/bktest$ ls -1 sample
CD01
CD02
CD03
CD04
CD05

--------

def main_work_subdirs(gl):
    for root, dirs, files in os.walk(gl['pwd']):
        if root == gl['pwd']:
            for d2i in dirs:
                print(d2i)

当python代码点击上面的目录时,输出如下:

ryan:~/bktest$ ~/test.py sample
CD03
CD01
CD05
CD02
CD04

我想强制 walk 按字母顺序访问这些目录,01, 02 ... 05。在python3 doc for os.walk 中,它说:

当 topdown 为 True 时,调用者可以就地修改目录名列表 (可能使用 del 或 slice 赋值),而 walk() 只会递归 进入名称保留在 dirnames 中的子目录;这可以是 用于修剪搜索,施加特定的访问顺序

这是否意味着我可以对os.walk 施加按字母顺序排列的访问顺序?如果有,怎么做?

【问题讨论】:

    标签: python-3.x os.walk


    【解决方案1】:

    是的。您在循环中对目录进行排序。

    def main_work_subdirs(gl):
        for root, dirs, files in os.walk(gl['pwd']):
            dirs.sort()
            if root == gl['pwd']:
                for d2i in dirs:
                    print(d2i)
    

    【讨论】:

    • 所以,这太棒了。我认为你对生成器唯一能做的就是迭代它们。
    • @ryan_m:这你能做的。但由于迭代中的下一步是在您完成第一个步骤之后才生成的,因此它允许使用这样的技巧。 :-)
    • 请明确一点,dirs 是一个列表,而不是生成器。
    • 我认为值得一提的一点是:它依赖于返回的dirs 对象被原地修改,因为os.walk 继续使用该列表。因此,如果您传递topdown=False,以便目录在 其内容之后生成,那么它将无法正常工作。同样,如果您使用dirs = sorted(dirs) 而不是dirs.sort(),它也将无法正常工作。
    • 好点 @wim 更多关于 sorted(bx) 和 x.sort() 之间的区别:stackoverflow.com/questions/22442378/…
    【解决方案2】:

    我知道这个问题已经得到解答,但我想添加一个小细节,并且在 cmets 中添加不止一行代码是很不靠谱的。

    除了希望对目录进行排序之外,我还希望对文件进行排序,以便通过“gl”进行的迭代是一致且可预测的。要做到这一点,需要再做一种:

    for root, dirs, files in os.walk(gl['pwd']):
      dirs.sort()
      for filename in sorted(files):
        print(os.path.join(root, filename))
    

    而且,通过学习更多关于 Python 的知识,一种不同的(更好的)方式:

    from pathlib import Path
    # Directories, per original question.
    [print(p) for p in sorted(Path(gl['pwd']).glob('**/*')) if p.is_dir()]
    # Files, like I usually need.
    [print(p) for p in sorted(Path(gl['pwd']).glob('**/*')) if p.is_file()]
    

    【讨论】:

      【解决方案3】:

      这个答案不是针对这个问题的,问题有点不同,但解决方案可以在任何一种情况下使用。 考虑拥有这些文件("one1.txt""one2.txt""one10.txt"),它们的内容都是一个字符串"default"

      我想遍历包含这些文件的目录并在每个文件中找到一个特定的字符串并将其替换为文件名。 如果您使用此处和其他问题中已经提到的任何其他方法(如dirs.sort()sorted(files)sorted(dirs),结果将是这样的:

      "one1.txt"--> "one10"
      "one2.txt"--> "one1"
      "one10.txt" --> "one2"
      

      但我们希望它是:

      "one1.txt"--> "one1"
      "one2.txt"--> "one2"
      "one10.txt" --> "one10"
      

      我发现了这种按字母顺序更改文件内容的方法:

      import re, os, fnmatch
      
      def atoi(text):
          return int(text) if text.isdigit() else text
      
      def natural_keys(text):
          '''
          alist.sort(key=natural_keys) sorts in human order
          http://nedbatchelder.com/blog/200712/human_sorting.html
          (See Toothy's implementation in the comments)
          '''
          return [ atoi(c) for c in re.split('(\d+)', text) ]
      
      def findReplace(directory, find, replace, filePattern):
          count = 0
          for path, dirs, files in sorted(os.walk(os.path.abspath(directory))):
              dirs.sort()
              for filename in sorted(fnmatch.filter(files, filePattern), key=natural_keys):
                  count = count +1
                  filepath = os.path.join(path, filename)
                  with open(filepath) as f:
                      s = f.read()
                  s = s.replace(find, replace+str(count)+".png")
                  with open(filepath, "w") as f:
                      f.write(s)
      

      然后运行这一行:

      findReplace(os.getcwd(), "default", "one", "*.xml")
      

      【讨论】:

        猜你喜欢
        • 2014-07-30
        • 2013-05-22
        • 2012-08-23
        • 2020-11-26
        • 1970-01-01
        • 2014-12-17
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多