使用os.walk()在Python中递归遍历目录

240
我希望从根目录导航到其中的所有其他目录并打印相同的内容。
这是我的代码:
#!/usr/bin/python

import os
import fnmatch

for root, dir, files in os.walk("."):
        print root
        print ""
        for items in fnmatch.filter(files, "*"):
                print "..." + items
        print ""

这是我的输出:

.

...Python_Notes
...pypy.py
...pypy.py.save
...classdemo.py
....goutputstream-J9ZUXW
...latest.py
...pack.py
...classdemo.pyc
...Python_Notes~
...module-demo.py
...filetype.py

./packagedemo

...classdemo.py
...__init__.pyc
...__init__.py
...classdemo.pyc

在上面的例子中,../packagedemo 是目录。

但是,我需要按以下方式输出结果:

A
---a.txt
---b.txt
---B
------c.out

上面的AB是目录,其余是文件。


7

我想在这里加一点关于Python的力量的小帖子: >>> print 2 * '--'

- Nitaai
14个回答

325

这将给你想要的结果。

#!/usr/bin/python

import os

# traverse root directory, and list directories as dirs and files as files
for root, dirs, files in os.walk("."):
    path = root.split(os.sep)
    print((len(path) - 1) * '---', os.path.basename(root))
    for file in files:
        print(len(path) * '---', file)

7
路径= os.path.relpath(根目录,基础路径)。split(os.sep) - Semprini
21
@Ajay要有点偏执,总是执行os.walk(u"."),因为路径可能是Unicode。 - Ciro Santilli OurBigBook.com
4
更好的是,os.path.curdir - Jir
我之前一直在使用 os.path.walk,所以 os.walk 对我来说是新的!太酷了。 - Tom
os.walk 隐藏了递归。但默认的 topdown 使递归可用:如果您就地过滤 dirs,则仅检查剩下的那些:https://docs.python.org/3/library/os.html#os.walk - Teepeemm
显示剩余2条评论

42

递归遍历一个目录,在当前目录下获取所有来自所有目录的文件,以及获取当前目录下的所有目录-因为上面的代码不够简单(个人认为):

for root, dirs, files in os.walk(rootFolderPath):
    for filename in files:
        doSomethingWithFile(os.path.join(root, filename))
    for dirname in dirs:
        doSomewthingWithDir(os.path.join(root, dirname))

11
最有帮助的答案。请注意,os.path.join(root, filename) 可以给出文件的完整路径,即使文件嵌套在多个目录中也可以。 - user1091458

38

试试这个:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""FileTreeMaker.py: ..."""

__author__  = "legendmohe"

import os
import argparse
import time

class FileTreeMaker(object):

    def _recurse(self, parent_path, file_list, prefix, output_buf, level):
        if len(file_list) == 0 \
            or (self.max_level != -1 and self.max_level <= level):
            return
        else:
            file_list.sort(key=lambda f: os.path.isfile(os.path.join(parent_path, f)))
            for idx, sub_path in enumerate(file_list):
                if any(exclude_name in sub_path for exclude_name in self.exn):
                    continue

                full_path = os.path.join(parent_path, sub_path)
                idc = "┣━"
                if idx == len(file_list) - 1:
                    idc = "┗━"

                if os.path.isdir(full_path) and sub_path not in self.exf:
                    output_buf.append("%s%s[%s]" % (prefix, idc, sub_path))
                    if len(file_list) > 1 and idx != len(file_list) - 1:
                        tmp_prefix = prefix + "┃  "
                    else:
                        tmp_prefix = prefix + "    "
                    self._recurse(full_path, os.listdir(full_path), tmp_prefix, output_buf, level + 1)
                elif os.path.isfile(full_path):
                    output_buf.append("%s%s%s" % (prefix, idc, sub_path))

    def make(self, args):
        self.root = args.root
        self.exf = args.exclude_folder
        self.exn = args.exclude_name
        self.max_level = args.max_level

        print("root:%s" % self.root)

        buf = []
        path_parts = self.root.rsplit(os.path.sep, 1)
        buf.append("[%s]" % (path_parts[-1],))
        self._recurse(self.root, os.listdir(self.root), "", buf, 0)

        output_str = "\n".join(buf)
        if len(args.output) != 0:
            with open(args.output, 'w') as of:
                of.write(output_str)
        return output_str

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-r", "--root", help="root of file tree", default=".")
    parser.add_argument("-o", "--output", help="output file name", default="")
    parser.add_argument("-xf", "--exclude_folder", nargs='*', help="exclude folder", default=[])
    parser.add_argument("-xn", "--exclude_name", nargs='*', help="exclude name", default=[])
    parser.add_argument("-m", "--max_level", help="max level",
                        type=int, default=-1)
    args = parser.parse_args()
    print(FileTreeMaker().make(args))

你将获得这个:

root:.
[.]
┣━[.idea]
┃  ┣━[scopes]
┃  ┃  ┗━scope_settings.xml
┃  ┣━.name
┃  ┣━Demo.iml
┃  ┣━encodings.xml
┃  ┣━misc.xml
┃  ┣━modules.xml
┃  ┣━vcs.xml
┃  ┗━workspace.xml
┣━[test1]
┃  ┗━test1.txt
┣━[test2]
┃  ┣━[test2-2]
┃  ┃  ┗━[test2-3]
┃  ┃      ┣━test2
┃  ┃      ┗━test2-3-1
┃  ┗━test2
┣━folder_tree_maker.py
┗━tree.py

你好,我真的很喜欢你的脚本,但对于我正在处理的项目来说有点太复杂了,有没有可能将其作为一个小函数,只包含-r参数? - jeff_h
如何将其打印到.txt文件中? 我尝试使用“print(FileTreeMaker().make(args),file=tree)”,但是它给出了“'charmap' codec can't encode characters in position 17-21: character maps to <undefined>” 的错误信息。 - L F
IDC代表什么? - voices
我也用了类似于 os.listdir() 的东西。但是你的方法更好,我无法正确地进行递归,只能在2或3层深度上工作。最终,我决定从头开始使用 os.walk(),因为我认为这更加合适。我很惊讶你在这里完全没有使用它。 - voices

14

os包中有更适合的函数。但如果你必须使用os.walk,这是我想出来的方法:

def walkdir(dirname):
    for cur, _dirs, files in os.walk(dirname):
        pref = ''
        head, tail = os.path.split(cur)
        while head:
            pref += '---'
            head, _tail = os.path.split(head)
        print(pref+tail)
        for f in files:
            print(pref+'---'+f)

输出:

>>> walkdir('.')
.
---file3
---file2
---my.py
---file1
---A
------file2
------file1
---B
------file3
------file2
------file4
------file1
---__pycache__
------my.cpython-33.pyc

9
那么什么样的功能更加适合?(如果有关系的话)(在Python 3.5中) - Al Lelopath
抱歉,我没有机会记住我当时的意思。可能我指的是 os.listdir,但 @ajay 的解决方案更好。 - zaquest

10

您也可以使用 pathlib.Path() 递归地遍历文件夹,并列出其中的所有内容。

from pathlib import Path


def check_out_path(target_path, level=0):
    """"
    This function recursively prints all contents of a pathlib.Path object
    """
    def print_indented(folder, level):
        print('\t' * level + folder)

    print_indented(target_path.name, level)
    for file in target_path.iterdir():
        if file.is_dir():
            check_out_path(file, level+1)
        else:
            print_indented(file.name, level+1)


my_path = Path(r'C:\example folder')
check_out_path(my_path)

输出:

example folder
    folder
        textfile3.txt
    textfile1.txt
    textfile2.txt

6
这里是文件夹名称的完整内容:
def printFolderName(init_indent, rootFolder):
    fname = rootFolder.split(os.sep)[-1]
    root_levels = rootFolder.count(os.sep)
    # os.walk treats dirs breadth-first, but files depth-first (go figure)
    for root, dirs, files in os.walk(rootFolder):
        # print the directories below the root
        levels = root.count(os.sep) - root_levels
        indent = ' '*(levels*2)
        print init_indent + indent + root.split(os.sep)[-1]

5
你可以使用os.walk,这可能是最简单的解决方案,但是这里有另一个值得探索的想法:
import sys, os

FILES = False

def main():
    if len(sys.argv) > 2 and sys.argv[2].upper() == '/F':
        global FILES; FILES = True
    try:
        tree(sys.argv[1])
    except:
        print('Usage: {} <directory>'.format(os.path.basename(sys.argv[0])))

def tree(path):
    path = os.path.abspath(path)
    dirs, files = listdir(path)[:2]
    print(path)
    walk(path, dirs, files)
    if not dirs:
        print('No subfolders exist')

def walk(root, dirs, files, prefix=''):
    if FILES and files:
        file_prefix = prefix + ('|' if dirs else ' ') + '   '
        for name in files:
            print(file_prefix + name)
        print(file_prefix)
    dir_prefix, walk_prefix = prefix + '+---', prefix + '|   '
    for pos, neg, name in enumerate2(dirs):
        if neg == -1:
            dir_prefix, walk_prefix = prefix + '\\---', prefix + '    '
        print(dir_prefix + name)
        path = os.path.join(root, name)
        try:
            dirs, files = listdir(path)[:2]
        except:
            pass
        else:
            walk(path, dirs, files, walk_prefix)

def listdir(path):
    dirs, files, links = [], [], []
    for name in os.listdir(path):
        path_name = os.path.join(path, name)
        if os.path.isdir(path_name):
            dirs.append(name)
        elif os.path.isfile(path_name):
            files.append(name)
        elif os.path.islink(path_name):
            links.append(name)
    return dirs, files, links

def enumerate2(sequence):
    length = len(sequence)
    for count, value in enumerate(sequence):
        yield count, count - length, value

if __name__ == '__main__':
    main()

您可能会在Windows终端的TREE命令中看到以下文档:
Graphically displays the folder structure of a drive or path.

TREE [drive:][path] [/F] [/A]

   /F   Display the names of the files in each folder.
   /A   Use ASCII instead of extended characters.

3

最好的方法是什么?

import os

def traverse_dir_recur(directory):
    l = os.listdir(directory)
    for d in l:
        if os.path.isdir(directory + d):
            traverse_dir_recur(directory +  d +"/")
        else:
            print(directory + d)

3
在Python3中对我不起作用。我认为错误在于 dir + d,它可能会在没有目录分隔符的情况下连接它们。最好使用os.path.join来连接目录和文件名。 - Zvika
你的反斜杠在这个答案中不正确。它们在两行中缺失,在递归调用的末尾也缺失。 - musterjunk

3
#!/usr/bin/python

import os 

def tracing(a):
    global i>
    for item in os.listdir(a):
        if os.path.isfile(item):
            print i + item 
        else:
            print i + item 
            i+=i
            tracing(item)

i = "---"
tracing(".")

2
给定一个文件夹名称,递归地遍历其整个层次结构。
#! /usr/local/bin/python3
# findLargeFiles.py - given a folder name, walk through its entire hierarchy
#                   - print folders and files within each folder

import os

def recursive_walk(folder):
    for folderName, subfolders, filenames in os.walk(folder):
        if subfolders:
            for subfolder in subfolders:
                recursive_walk(subfolder)
        print('\nFolder: ' + folderName + '\n')
        for filename in filenames:
            print(filename + '\n')

recursive_walk('/name/of/folder')

5
不需要递归调用os.walk,因为它已经将递归展平。这就是为什么它会返回folderName参数的原因。 - gwideman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接