Как использовать glob() для рекурсивного поиска файлов?
Это то, что у меня есть:
glob(os.path.join('src','*.c'))
но я хочу искать подпапки src. Что-то вроде этого будет работать:
glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))
Но это явно ограничено и неуклюже.
Ответы
Ответ 1
Python 3. 5+
Поскольку вы находитесь на новом pathlib.Path.glob
, вы должны использовать pathlib.Path.glob
из модуля pathlib
.
from pathlib import Path
for filename in Path('src').glob('**/*.c'):
print(filename)
Если вы не хотите использовать pathlib, просто используйте glob.glob
, но не забудьте передать параметр recursive
ключевого слова.
Для случаев, когда совпадающие файлы начинаются с точки (.); как файлы в текущем каталоге или скрытые файлы в системе на основе Unix, используйте решение os.walk
ниже.
Старые версии Python
Для более старых версий Python используйте os.walk
для рекурсивного fnmatch.filter
каталога и fnmatch.filter
для сопоставления с простым выражением:
import fnmatch
import os
matches = []
for root, dirnames, filenames in os.walk('src'):
for filename in fnmatch.filter(filenames, '*.c'):
matches.append(os.path.join(root, filename))
Ответ 2
Подобно другим решениям, но используя fnmatch.fnmatch вместо glob, поскольку os.walk уже перечисляет имена файлов:
import os, fnmatch
def find_files(directory, pattern):
for root, dirs, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
filename = os.path.join(root, basename)
yield filename
for filename in find_files('src', '*.c'):
print 'Found C source:', filename
Также, используя генератор, вы должны обрабатывать каждый файл, как он найден, вместо того, чтобы находить все файлы и затем обрабатывать их.
Ответ 3
Я модифицировал модуль glob для поддержки ** для рекурсивного globbing, например:
>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')
https://github.com/miracle2k/python-glob2/
Полезно, если вы хотите предоставить своим пользователям возможность использовать синтаксис **, и, следовательно, os.walk() не достаточно хорош.
Ответ 4
Начиная с Python 3.4, можно использовать метод glob()
одного из классов Path
в новом pathlib, который поддерживает **
подстановочные знаки. Например:
from pathlib import Path
for file_path in Path('src').glob('**/*.c'):
print(file_path) # do whatever you need with these files
Update:
Начиная с Python 3.5, тот же синтаксис также поддерживается glob.glob()
.
Ответ 5
import os
import fnmatch
def recursive_glob(treeroot, pattern):
results = []
for base, dirs, files in os.walk(treeroot):
goodfiles = fnmatch.filter(files, pattern)
results.extend(os.path.join(base, f) for f in goodfiles)
return results
fnmatch
дает вам точно такие же шаблоны, как glob
, так что это действительно отличная замена для glob.glob
с очень близкой семантикой. Итеративная версия (например, генератор), IOW - замена для glob.iglob
, - это тривиальная адаптация (просто yield
промежуточные результаты по мере того, как вы идете, вместо extend
, чтобы один список результатов возвращался в конце).
Ответ 6
Вы хотите использовать os.walk
для сбора имен файлов, соответствующих вашим критериям. Например:
import os
cfiles = []
for root, dirs, files in os.walk('src'):
for file in files:
if file.endswith('.c'):
cfiles.append(os.path.join(root, file))
Ответ 7
Вот решение с вложенными списками, os.walk
и простое совпадение суффикса вместо glob
:
import os
cfiles = [os.path.join(root, filename)
for root, dirnames, filenames in os.walk('src')
for filename in filenames if filename.endswith('.c')]
Его можно сжать в однострочный:
import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')]
или обобщен как функция:
import os
def recursive_glob(rootdir='.', suffix=''):
return [os.path.join(looproot, filename)
for looproot, _, filenames in os.walk(rootdir)
for filename in filenames if filename.endswith(suffix)]
cfiles = recursive_glob('src', '.c')
Если вам нужны полные стили стиля glob
, вы можете следить за Алексом и
Пример Bruno и используйте fnmatch
:
import fnmatch
import os
def recursive_glob(rootdir='.', pattern='*'):
return [os.path.join(looproot, filename)
for looproot, _, filenames in os.walk(rootdir)
for filename in filenames
if fnmatch.fnmatch(filename, pattern)]
cfiles = recursive_glob('src', '*.c')
Ответ 8
Недавно мне пришлось восстановить мои фотографии с расширением .jpg. Я запустил photorec и восстановил 4579 каталогов 2,2 миллиона файлов внутри, имея огромное разнообразие расширений. С script ниже я смог выбрать 50133 файлов havin.jpg расширение в течение минут:
#!/usr/binenv python2.7
import glob
import shutil
import os
src_dir = "/home/mustafa/Masaüstü/yedek"
dst_dir = "/home/mustafa/Genel/media"
for mediafile in glob.iglob(os.path.join(src_dir, "*", "*.jpg")): #"*" is for subdirectory
shutil.copy(mediafile, dst_dir)
Ответ 9
Йохан и Бруно предлагают отличные решения по минимальным требованиям, как указано. Я только что выпустил Formic, который реализует Ant FileSet и Globs, который может справиться с этим и более сложным сценарии. Реализация вашего требования:
import formic
fileset = formic.FileSet(include="/src/**/*.c")
for file_name in fileset.qualified_files():
print file_name
Ответ 10
основанный на других ответах, это моя текущая рабочая реализация, которая извлекает вложенные XML файлы в корневой каталог:
files = []
for root, dirnames, filenames in os.walk(myDir):
files.extend(glob.glob(root + "/*.xml"))
Мне очень весело с python:)
Ответ 11
Рассмотрим pathlib.rglob()
.
Это похоже на вызов Path.glob()
с добавлением "**/"
перед данным относительным шаблоном:
import pathlib
for p in pathlib.Path("src").rglob("*.c"):
print(p)
Смотрите также @taleinat, связанный пост здесь и более ранний пост в другом месте.
Ответ 12
Другой способ сделать это, используя только модуль glob. Просто запустите метод rglob с исходным базовым каталогом и шаблоном для соответствия, и он вернет список совпадающих имен файлов.
import glob
import os
def _getDirs(base):
return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ]
def rglob(base, pattern):
list = []
list.extend(glob.glob(os.path.join(base,pattern)))
dirs = _getDirs(base)
if len(dirs):
for d in dirs:
list.extend(rglob(os.path.join(base,d), pattern))
return list
Ответ 13
Просто сделал это.. он будет печатать файлы и каталог иерархическим способом
Но я не использовал fnmatch или ходить
#!/usr/bin/python
import os,glob,sys
def dirlist(path, c = 1):
for i in glob.glob(os.path.join(path, "*")):
if os.path.isfile(i):
filepath, filename = os.path.split(i)
print '----' *c + filename
elif os.path.isdir(i):
dirname = os.path.basename(i)
print '----' *c + dirname
c+=1
dirlist(i,c)
c-=1
path = os.path.normpath(sys.argv[1])
print(os.path.basename(path))
dirlist(path)
Ответ 14
Этот использует fnmatch или регулярное выражение:
import fnmatch, os
def filepaths(directory, pattern):
for root, dirs, files in os.walk(directory):
for basename in files:
try:
matched = pattern.match(basename)
except AttributeError:
matched = fnmatch.fnmatch(basename, pattern)
if matched:
yield os.path.join(root, basename)
# usage
if __name__ == '__main__':
from pprint import pprint as pp
import re
path = r'/Users/hipertracker/app/myapp'
pp([x for x in filepaths(path, re.compile(r'.*\.py$'))])
pp([x for x in filepaths(path, '*.py')])
Ответ 15
В дополнение к предлагаемым ответам вы можете сделать это с помощью ленивого поколения и магии понимания списка:
import os, glob, itertools
results = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.c'))
for root, dirs, files in os.walk('src'))
for f in results: print(f)
Помимо установки в одной строке и исключения ненужных списков в памяти, у этого также есть хороший побочный эффект, который вы можете использовать его так же, как оператор **, например, вы могли бы использовать os.path.join(root, 'some/path/*.c')
, чтобы получить все .c файлы во всех подкаталогах src, которые имеют эту структуру.
Ответ 16
Упрощенная версия ответа Йохана Дахлина без fnmatch.
import os
matches = []
for root, dirnames, filenames in os.walk('src'):
matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c']
Ответ 17
Или со списком:
>>> base = r"c:\User\xtofl"
>>> binfiles = [ os.path.join(base,f)
for base, _, files in os.walk(root)
for f in files if f.endswith(".jpg") ]
Ответ 18
Вот мое решение, использующее понимание списков для поиска нескольких расширений файлов рекурсивно в каталоге и во всех подкаталогах:
import os, glob
def _globrec(path, *exts):
""" Glob recursively a directory and all subdirectories for multiple file extensions
Note: Glob is case-insensitive, i. e. for '\*.jpg' you will get files ending
with .jpg and .JPG
Parameters
----------
path : str
A directory name
exts : tuple
File extensions to glob for
Returns
-------
files : list
list of files matching extensions in exts in path and subfolders
"""
dirs = [a[0] for a in os.walk(path)]
f_filter = [d+e for d in dirs for e in exts]
return [f for files in [glob.iglob(files) for files in f_filter] for f in files]
my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif')
for f in my_pictures:
print f
Ответ 19
Для python> = 3.5 вы можете использовать **
, recursive=True
:
import glob
for x in glob.glob('path/**/*.c', recursive=True):
print(x)
Demo
Если рекурсивный имеет значение true, шаблон **
будет соответствовать любым файлам и нулю или более directories
и subdirectories
. Если шаблон сопровождается os.sep
, только каталоги и subdirectories
совпадают.
Ответ 20
import sys, os, glob
dir_list = ["c:\\books\\heap"]
while len(dir_list) > 0:
cur_dir = dir_list[0]
del dir_list[0]
list_of_files = glob.glob(cur_dir+'\\*')
for book in list_of_files:
if os.path.isfile(book):
print(book)
else:
dir_list.append(book)
Ответ 21
Я изменил верхний ответ в этой публикации.. и недавно создал этот script, который будет перебирать все файлы в данном каталоге (searchdir) и подкаталоги под ним... и печатает имя файла, rootdir, изменено/дату создания и размер.
Надеюсь, это поможет кому-то... и они могут ходить по каталогу и получать файлinfo.
import time
import fnmatch
import os
def fileinfo(file):
filename = os.path.basename(file)
rootdir = os.path.dirname(file)
lastmod = time.ctime(os.path.getmtime(file))
creation = time.ctime(os.path.getctime(file))
filesize = os.path.getsize(file)
print "%s**\t%s\t%s\t%s\t%s" % (rootdir, filename, lastmod, creation, filesize)
searchdir = r'D:\Your\Directory\Root'
matches = []
for root, dirnames, filenames in os.walk(searchdir):
## for filename in fnmatch.filter(filenames, '*.c'):
for filename in filenames:
## matches.append(os.path.join(root, filename))
##print matches
fileinfo(os.path.join(root, filename))
Ответ 22
Вот решение, которое будет соответствовать шаблону в отношении полного пути, а не только базового имени файла.
Он использует fnmatch.translate
, чтобы преобразовать шаблон стиля glob в регулярное выражение, которое затем сопоставляется с полным путем каждого файла найденный во время ходьбы по каталогу.
re.IGNORECASE
является необязательным, но желательным для Windows, поскольку сама файловая система не чувствительна к регистру. (Я не собирался компилировать регулярное выражение, потому что документы указывают, что он должен быть кэширован внутренне.)
import fnmatch
import os
import re
def findfiles(dir, pattern):
patternregex = fnmatch.translate(pattern)
for root, dirs, files in os.walk(dir):
for basename in files:
filename = os.path.join(root, basename)
if re.search(patternregex, filename, re.IGNORECASE):
yield filename
Ответ 23
Мне нужно решение для python 2.x, которое работает быстро на больших каталогах.
Я поддерживаю это:
import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
print foundfile
Обратите внимание, что вам может понадобиться некоторая обработка исключений в случае, если ls
не находит соответствующий файл.
Ответ 24
Для Python 3.5 и более поздних версий
file_names_array = glob.glob('src/*.c', recursive=True)
Редактировать: руководствуясь @NeStack, если описанное выше не работает, попробуйте
file_names_array = glob.glob('src/**.c', recursive=True)
дальше вам может понадобиться
for full_path_in_src in file_names_array:
print (full_path_in_src ) # be like 'abc/xyz.c'
#Full system path of this would be like => 'path till src/abc/xyz.c'