Рекурсивная подпапка поиска и возврата файлов в списке python
Я работаю над script, чтобы рекурсивно пройти через подпапки в основной папке и создать список с определенного типа файла. У меня проблема с script. В настоящее время он установлен следующим образом
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 для подпапки раньше и присоединяюсь к первой части пути, но я решил дважды проверить Id, чтобы увидеть, есть ли у кого-либо предложения до этого. Спасибо за вашу помощь!
Ответы
Ответ 1
Вы должны использовать 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']
Редактировать:
После последнего понижения мне пришло в голову, что 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]"))
Ответ 2
Изменено в 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):
# ...
Ответ 3
Я переведу понимание списка Джона Ля Роя на nested, на тот случай, если у кого-то еще возникнут проблемы с его пониманием.
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.
Ответ 4
Это не самый пифонический ответ, но я положу его сюда для удовольствия, потому что это аккуратный урок в рекурсии
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
Новая библиотека 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
.
Ответ 6
Рекурсивная новинка в 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
Примечание: в нем будут перечислены все файлы, независимо от их глубины.
Ответ 7
Эта функция рекурсивно помещает в список только файлы. Надеюсь, что так и будет.
import os
def ls_files(dir):
files = list()
for item in os.listdir(dir):
abspath = os.path.join(dir, item)
try:
if os.path.isdir(abspath):
files = files + ls_files(abspath)
else:
files.append(abspath)
except FileNotFoundError as err:
print('invalid directory\n', 'Error: ', err)
return files