递归子文件夹搜索并返回列表python中的文件

Recursive sub folder search and return files in a list python

我正在编写一个脚本,递归地遍历主文件夹中的子文件夹,并根据某个文件类型构建一个列表。我对剧本有意见。其当前设置如下

1
2
3
4
for root, subFolder, files in os.walk(PATH):
    for item in files:
        if item.endswith(".txt") :
            fileNamePath = str(os.path.join(root,subFolder,item))

问题是子文件夹变量正在拉入子文件夹列表,而不是项目文件所在的文件夹。我之前在考虑为子文件夹运行for循环,并加入路径的第一部分,但是我想再次检查一下是否有人在此之前有任何建议。谢谢你的帮助!


你应该使用你称之为rootdirpath。提供了dirnames,因此如果有不希望os.walk重现的文件夹,可以对其进行修剪。

1
2
import os
result = [os.path.join(dp, f) for dp, dn, filenames in os.walk(PATH) for f in filenames if os.path.splitext(f)[1] == '.txt']

编辑:

在最近一次投票否决之后,我突然想到,glob是一个更好的工具,可以通过扩展进行选择。

1
2
3
import os
from glob import glob
result = [y for x in os.walk(PATH) for y in glob(os.path.join(x[0], '*.txt'))]

也是发电机版本

1
2
from itertools import chain
result = (chain.from_iterable(glob(os.path.join(x[0], '*.txt')) for x in os.walk('.')))

针对python 3.4的edit2+

1
2
from pathlib import Path
result = list(Path(".").rglob("*.[tT][xX][tT]"))


Changed in Python 3.5: Support for recursive globs using"**".

glob.glob()得到了一个新的递归参数。

如果要获取my_path下的每个.txt文件(递归地包括子目录):

1
2
3
4
5
6
7
import glob

files = glob.glob(my_path + '/**/*.txt', recursive=True)

# my_path/     the dir
# **/       every file and dir under my_path
# *.txt     every file that ends with '.txt'

如果需要迭代器,可以使用iglob作为替代:

1
2
for file in glob.iglob(my_path, recursive=False):
    # ...


我会把约翰·拉罗伊的清单理解翻译成嵌套的for,以防其他人无法理解。

1
result = [y for x in os.walk(PATH) for y in glob(os.path.join(x[0], '*.txt'))]

应等于:

1
2
3
4
5
result = []

for x in os.walk(PATH):
    for y in glob(os.path.join(x[0], '*.txt')):
        result.append(y)

以下是列表理解和os.walk和glob.glob函数的文档。


这不是最简单的Python式的答案,但我会把它放在这里玩,因为这是一个很好的递归课程。

1
2
3
4
5
6
7
8
9
10
11
12
13
def find_files( files, dirs=[], extensions=[]):
    new_dirs = []
    for d in dirs:
        try:
            new_dirs += [ os.path.join(d, f) for f in os.listdir(d) ]
        except OSError:
            if os.path.splitext(d)[1] in extensions:
                files.append(d)

    if new_dirs:
        find_files(files, new_dirs, extensions )
    else:
        return

在我的机器上,我有两个文件夹:rootroot2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mender@multivax ]ls -R root root2
root:
temp1 temp2

root/temp1:
temp1.1 temp1.2

root/temp1/temp1.1:
f1.mid

root/temp1/temp1.2:
f.mi  f.mid

root/temp2:
tmp.mid

root2:
dummie.txt temp3

root2/temp3:
song.mid

假设我想在这些目录中找到所有.txt和所有.mid文件,那么我可以

1
2
3
4
5
6
7
8
9
files = []
find_files( files, dirs=['root','root2'], extensions=['.mid','.txt'] )
print(files)

#['root2/dummie.txt',
# 'root/temp2/tmp.mid',
# 'root2/temp3/song.mid',
# 'root/temp1/temp1.1/f1.mid',
# 'root/temp1/temp1.2/f.mid']

新的pathlib库将此简化为一行:

1
2
from pathlib import Path
result = list(Path(PATH).glob('**/*.txt'))

您还可以使用生成器版本:

1
2
3
from pathlib import Path
for file in Path(PATH).glob('**/*.txt'):
    pass

这将返回Path对象,您可以将其用于几乎所有内容,或者通过file.name以字符串形式获取文件名。