【问题标题】:Do I understand os.walk right?我理解 os.walk 对吗?
【发布时间】:2012-06-12 00:01:53
【问题描述】:

os.walk(startdir) 中的 root、dir、file 循环通过这些步骤工作?

for root in os.walk(startdir) 
    for dir in root 
        for files in dir
  1. 获取起始目录的根目录:C:\dir1\dir2\startdir

  2. 获取 C:\dir1\dir2\startdir 中的文件夹并返回文件夹列表“dirlist”

  3. 在第一个 dirlist 项中获取文件,并将文件列表“filelist”作为文件列表列表的第一项返回。

  4. 移动到 dirlist 中的第二项并返回此文件夹“filelist2”中的文件列表作为文件列表列表的第二项。等等

  5. 移动到文件夹树中的下一个根目录并从 2. 等开始

对吗?还是首先获取所有根目录,然后是所有目录,然后是所有文件?

【问题讨论】:

  • 我喜欢使用这个生成器来循环所有文件:get_files = lambda path: (os.path.join(root, file) for root, dirs, files in os.walk(path) for file in files)。然后你可以使用for file in get_files(path): ...

标签: python file


【解决方案1】:

os.walk 返回一个生成器,它创建一个值元组(current_path、current_path 中的目录、current_path 中的文件)。

每次调用生成器时,它都会递归地跟随每个目录,直到调用 walk 的初始目录中没有其他子目录可用。

因此,

os.walk('C:\dir1\dir2\startdir').next()[0] # returns 'C:\dir1\dir2\startdir'
os.walk('C:\dir1\dir2\startdir').next()[1] # returns all the dirs in 'C:\dir1\dir2\startdir'
os.walk('C:\dir1\dir2\startdir').next()[2] # returns all the files in 'C:\dir1\dir2\startdir'

所以

import os.path
....
for path, directories, files in os.walk('C:\dir1\dir2\startdir'):
     if file in files:
          print('found %s' % os.path.join(path, file))

或者这个

def search_file(directory = None, file = None):
    assert os.path.isdir(directory)
    for cur_path, directories, files in os.walk(directory):
        if file in files:
            return os.path.join(directory, cur_path, file)
    return None

或者如果你想查找文件,你可以这样做:

import os
def search_file(directory = None, file = None):
    assert os.path.isdir(directory)
    current_path, directories, files = os.walk(directory).next()
    if file in files:
        return os.path.join(directory, file)
    elif directories == '':
        return None
    else:
        for new_directory in directories:
            result = search_file(directory = os.path.join(directory, new_directory), file = file)
            if result:
                return result
        return None

【讨论】:

  • 我喜欢 os.path 解决方案,所以 os.path 将始终对应 os.walk 在该迭代期间所在的目录?
  • 顺便说一句,以上所有答案都值得一个答案标签,但我只能将其中一个帖子标记为答案!不好,或者有没有办法将多个帖子标记为答案?
  • 哦还有一件事,你为什么要导入 os 和 os.path?导入os时不包含os.path吗?
  • os 模块是一个 23k 行的野兽,但是是的,import os.path 不是必需的,尽管我记得我曾经遇到过一个问题,但不记得是什么了,无论如何 os.path 是处理路径os.path.join 的最安全方式它将在任何操作系统中自动生成适当的join,在Windows 中它知道它们应该'\'并在*nix 中转义它知道它们应该是/ 并且它知道什么时候组合目录或只是文件,它非常聪明:)
  • Python 3 注意:next(os.walk('C:\dir1\dir2\startdir'))[0]
【解决方案2】:

最小可运行示例

这就是我喜欢学习的方式:

mkdir root
cd root
mkdir \
  d0 \
  d1 \
  d0/d0_d1
touch \
  f0 \
  d0/d0_f0 \
  d0/d0_f1 \
  d0/d0_d1/d0_d1_f0
tree

输出:

.
├── d0
│   ├── d0_d1
│   │   └── d0_d1_f0
│   ├── d0_f0
│   └── d0_f1
├── d1
└── f0

main.py

#!/usr/bin/env python3
import os
for path, dirnames, filenames in os.walk('root'):
    print('{} {} {}'.format(repr(path), repr(dirnames), repr(filenames)))

输出:

'root' ['d0', 'd1'] ['f0']
'root/d0' ['d0_d1'] ['d0_f0', 'd0_f1']
'root/d0/d0_d1' [] ['d0_d1_f0']
'root/d1' [] []

这让一切都清楚了:

  • path是每一步的根目录
  • dirnames 是每个path 中的目录基名列表
  • filenames 是每个 path 中的文件基名列表

在 Ubuntu 16.04、Python 3.5.2 上测试。

修改dirnames会改变树递归

这基本上是您必须记住的唯一其他事情。

例如对dirnames进行如下操作,会影响遍历:

遍历文件或目录

如果要遍历的输入是文件或目录,则可以这样处理:

#!/usr/bin/env python3

import os
import sys

def walk_file_or_dir(root):
    if os.path.isfile(root):
        dirname, basename = os.path.split(root)
        yield dirname, [], [basename]
    else:
        for path, dirnames, filenames in os.walk(root):
            yield path, dirnames, filenames

for path, dirnames, filenames in walk_file_or_dir(sys.argv[1]):
    print(path, dirnames, filenames)

【讨论】:

    【解决方案3】:

    简单来说,os.walk() 将生成路径、文件夹、给定路径中存在的文件的元组,并将继续遍历子文件夹。

    import os.path
    path=input(" enter the path\n")
    for path,subdir,files in os.walk(path):
       for name in subdir:
           print os.path.join(path,name) # will print path of directories
       for name in files:    
           print os.path.join(path,name) # will print path of files
    

    这将生成所有子目录、文件和子目录中文件的路径

    【讨论】:

      【解决方案4】:

      这里有一个简短的例子来说明os.walk() 的工作原理以及使用一些os 函数的一些解释。

      首先注意os.walk() 返回三个 项、根目录、当前根目录下的目录列表 (dirs) 以及在这些目录中找到的文件列表。 documentation 将为您提供更多信息。

      dirs 将包含根目录下的目录列表,而 files 将包含在这些目录中找到的所有文件的列表。在下一次迭代中,之前dirs 列表中的每个目录将依次扮演root 的角色,并且从那里继续搜索,只有在搜索完当前级别后才会下一层。

      代码示例:这将在指定搜索目录(您的根目录)下搜索、计算和打印.jpg.gif 文件的名称。它还利用os.path.splitext() 函数将文件的基础与其扩展名分开,并利用os.path.join() 函数为您提供包含找到的图像文件的全名。

      import os
      
      searchdir = r'C:\your_root_dir'  # your search starts in this directory (your root) 
      
      count = 0
      for root, dirs, files in os.walk(searchdir):
          for name in files:
              (base, ext) = os.path.splitext(name) # split base and extension
              if ext in ('.jpg', '.gif'):          # check the extension
                  count += 1
                  full_name = os.path.join(root, name) # create full path
                  print(full_name)
      
      print('\ntotal number of .jpg and .gif files found: %d' % count)
      

      【讨论】:

      【解决方案5】:

      os.walk 的工作方式与上面的略有不同。基本上,它返回(路径、目录、文件)的元组。要查看此内容,请尝试以下操作:

      import pprint
      import os
      pp=pprint.PrettyPrinter(indent=4)
      for dir_tuple in os.walk("/root"):
          pp.pprint(dir_tuple)
      

      ...您将看到循环的每次迭代都将打印一个目录名称、该目录中所有目录的名称列表以及该目录中所有文件的另一个列表。 os.walk 然后会进入子目录列表中的每个目录,并做同样的事情,直到原根目录的所有子目录都被遍历完。了解一些有关递归的知识以了解其工作原理可能会有所帮助。

      【讨论】:

        【解决方案6】:

        我的回答非常简单明了。我自己是一个初学者,在网上找到了我的答案(见特别是the good documentation at docs.python.org)并尝试了一些测试代码,比如这个:

        for root, dirs, files in os.walk(startdir)
            print ("__________________")
            print (root)
            for file in files:
                print ("---",file)
        

        这会打印出目录树,其中每个目录(起始目录和包含的子目录)前面都有一行,后面是其中包含的文件。

        我认为你必须记住两件事:

        (1) os.walk 生成一个三元组(一个三元组) where

        • root 是一个字符串,包含根目录的名称;

        • dirs 是字符串的list:根目录中直接包含的目录名,即第一级,不包含可能包含的子目录 他们;

        • 文件名是字符串的列表:直接包含在根目录中的文件名。

        (2) 一个for循环比如

        for root, subdirs, files in os.walk(YourStartDir)
        

        遍历根目录及其所有子目录。每个文件都不需要一个步骤;它只是扫描目录树,并在每一步(对于树中的每个目录)填充其中包含的文件名列表和直接包含在其中的子目录列表。如果您有 n 个目录(包括根目录及其子目录),for 循环将循环 n 次,即 它需要 n 个步骤。 您可以编写一小段测试代码来检查这一点,例如使用计数器。 在每一步,它都会生成一个 3 元组:一个字符串加上两个(可能是空的)字符串列表。 在本例中,三元组的元素被称为:“root”、“subdirs”、“files”,但这些名称由您决定;如果你的代码是

        for a, b, c in os.walk(startdir)
        

        三元组的元素将被称为“a”、“b”、“c”。

        让我们回到测试代码:

        for root, dirs, files in os.walk(startdir)
            print ("__________________")
            print (root)
            for file in files:
                print ("---",file)
        

        第一个循环:root 是您在输入中给出的目录(起始路径,起始目录:一个字符串),dirs 是包含的子目录名称的列表(但不是名称其中包含的目录),files 是包含文件的列表。在测试代​​码中,我们没有使用“dirs”列表。

        第二个循环:root 现在是第一个子目录,dirs 是其中包含的子目录的列表,files 是其中包含的文件的列表。

        ... 以此类推,直到到达树中的最后一个子目录。

        os.walk 有三个可选参数:你可以在网上找到很多关于它们及其使用的信息,但我认为你的问题是关于 os.walk 的基础知识。

        【讨论】:

          猜你喜欢
          • 2020-05-13
          • 1970-01-01
          • 2011-02-01
          • 1970-01-01
          • 2012-01-27
          • 2021-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多