it-swarm.com.ru

Рекурсивный поиск по подпапкам и возврат файлов в списке python

Я работаю над сценарием для рекурсивного просмотра подпапок в основной папке и построения списка из файлов определенного типа. У меня проблема со сценарием. В настоящее время установлено следующее

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

проблема в том, что переменная subFolder извлекает список подпапок, а не папку, в которой находится файл ITEM. Я думал о том, чтобы запустить цикл for для подпапки и присоединиться к первой части пути, но я подумал, что я должен дважды проверить, есть ли у кого-нибудь какие-либо предложения до этого. Спасибо за вашу помощь!

83
user2709514

Вы должны использовать dirpath, который вы называете root. dirnames предоставлены, так что вы можете сократить его, если есть папки, в которые вы не хотите, чтобы os.walk возвращался.

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']

Edit:

После последнего понижения мне пришло в голову, что glob - лучший инструмент для выбора по расширению.

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

Также версия генератора

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

Edit2 для Python 3.4 +

from pathlib import Path
result = list(Path(".").rglob("*.[tT][xX][tT]"))
127
John La Rooy

Изменено в Python 3.5 : поддержка рекурсивных глобусов с использованием "**".

glob.glob() получил новый рекурсивный параметр .

Если вы хотите получить каждый .txt файл в my_path (рекурсивно, включая подкаталоги):

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 в качестве альтернативы:

for file in glob.iglob(my_path, recursive=False):
    # ...
68
Rotareti

Я переведу понимание списка Джона Ла Руи к вложенным для, на тот случай, если у кого-то еще возникнут проблемы с его пониманием.

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

Должно быть эквивалентно:

import glob

result = []

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

Вот документация для понимание списка и функций os.walk и glob.glob .

14
Jefferson Lima

Это не самый питонский ответ, но я поставлю его здесь для удовольствия, потому что это аккуратный урок рекурсии

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

На моей машине у меня есть две папки: root и root2

[email protected] ]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 файлы в любом из этих каталогов, тогда я могу просто сделать

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']
5
dermen

Новая библиотека pathlib упрощает это до одной строки:

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

Вы также можете использовать версию генератора:

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

Это возвращает Path объекты, которые вы можете использовать практически для чего угодно, или получить имя файла в виде строки с помощью file.name.

4
Emre

Рекурсивность появилась в Python 3.5, поэтому она не будет работать в Python 2.7. Вот пример, в котором используются строки r, поэтому вам просто нужно указать путь как в Win, Lin, ...

import glob

mypath=r"C:\Users\dj\Desktop\nba"

files = glob.glob(mypath + r'\**\*.py', recursive=True)
# print(files) # as list
for f in files:
    print(f) # Nice looking single line per file

Примечание: в нем будут перечислены все файлы, независимо от их глубины.

0
prosti