files - ¿Usar un Glob() para encontrar archivos recursivamente en Python?
glob.glob python (21)
Esto es lo que tengo:
glob(os.path.join(''src'',''*.c''))
pero quiero buscar las subcarpetas de src. Algo como esto funcionaría:
glob(os.path.join(''src'',''*.c''))
glob(os.path.join(''src'',''*'',''*.c''))
glob(os.path.join(''src'',''*'',''*'',''*.c''))
glob(os.path.join(''src'',''*'',''*'',''*'',''*.c''))
Pero esto es obviamente limitado y torpe.
Acaba de hacer esto .. se imprimirán los archivos y directorios de forma jerárquica
Pero no utilicé fnmatch o walk
#!/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)
Además de las respuestas sugeridas, puede hacer esto con un poco de generación perezosa y una lista de comprensión mágica:
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)
Además de encajar en una línea y evitar listas innecesarias en la memoria, esto también tiene el efecto secundario agradable, que puede usarlo de manera similar al operador **, por ejemplo, podría usar os.path.join(root, ''some/path/*.c'')
para obtener todos los archivos .c en todos los subdirectorios de src que tienen esta estructura.
Aquí está mi solución usando la comprensión de lista para buscar múltiples extensiones de archivo recursivamente en un directorio y todos los subdirectorios:
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
Aquí hay una solución con listas de comprensión anidadas, os.walk
y coincidencia de sufijo simple en lugar de 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'')]
Se puede comprimir en una sola línea:
import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk(''src'') for f in fs if f.endswith(''.c'')]
o generalizada como una función:
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'')
Si necesita patrones de estilo glob
, puede seguir el ejemplo de Alex y Bruno y usar 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'')
Aquí hay una solución que hará coincidir el patrón con la ruta completa y no solo con el nombre de archivo base.
Utiliza fnmatch.translate
para convertir un patrón de estilo glob en una expresión regular, que luego se compara con la ruta completa de cada archivo encontrado mientras recorre el directorio.
re.IGNORECASE
es opcional, pero deseable en Windows ya que el sistema de archivos en sí no re.IGNORECASE
mayúsculas y minúsculas. (No me molesté en compilar la expresión regular porque los documentos indican que debe guardarse en caché internamente).
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
Comenzando con Python 3.4, se puede usar el método glob()
de una de las clases de Path
en el nuevo módulo pathlib , que admite **
comodines. Por ejemplo:
from pathlib import Path
for file_path in Path(''src'').glob(''**/*.c''):
print(file_path) # do whatever you need with these files
Actualización: A partir de Python 3.5, glob.glob()
también admite la misma sintaxis.
He modificado el módulo glob para que sea compatible con ** para globazas recursivas, por ejemplo:
>>> import glob2
>>> all_header_files = glob2.glob(''src/**/*.c'')
https://github.com/miracle2k/python-glob2/
Es útil cuando desea proporcionar a sus usuarios la capacidad de usar la sintaxis **, y por lo tanto, os.walk () solo no es lo suficientemente bueno.
Johan y Bruno proporcionan excelentes soluciones en los requisitos mínimos tal como se indica. Acabo de lanzar Formic que implementa Ant FileSet y Globs que pueden manejar esto y otros escenarios más complicados. Una implementación de su requerimiento es:
import formic
fileset = formic.FileSet(include="/src/**/*.c")
for file_name in fileset.qualified_files():
print file_name
Modifiqué la respuesta principal en esta publicación ... y recientemente creé esta secuencia de comandos que recorrerá todos los archivos en un directorio determinado (searchdir) y los subdirectorios debajo de él ... e imprime el nombre de archivo, rootdir, fecha de creación / modificación, y tamaño.
Espero que esto ayude a alguien ... y puedan recorrer el directorio y obtener información del archivo.
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))
Necesitaba una solución para Python 2.x que funcione rápidamente en directorios grandes.
Terminé con esto:
import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
print foundfile
Tenga en cuenta que es posible que necesite un manejo de excepciones en caso de que ls
no encuentre ningún archivo coincidente.
O con una lista de comprensión:
>>> 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") ]
Otra forma de hacerlo solo con el módulo glob. Simplemente agregue el método rglob con un directorio base de inicio y un patrón para que coincida, y devolverá una lista de nombres de archivos coincidentes.
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
Que uno usa fnmatch o expresión regular:
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'')])
Recientemente tuve que recuperar mis fotos con la extensión .jpg. Corrí fotorec y recuperé 4579 directorios con 2,2 millones de archivos en el interior, con una gran variedad de extensiones. Con el siguiente script, pude seleccionar 50133 archivos con la extensión .jpg en cuestión de minutos:
#!/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)
Similar a otras soluciones, pero usando fnmatch.fnmatch en lugar de glob, ya que os.walk ya enumeró los nombres de archivo:
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
Además, el uso de un generador le permite procesar cada archivo a medida que se encuentra, en lugar de encontrar todos los archivos y luego procesarlos.
Versión simplificada de la respuesta de Johan Dahlin, sin 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'']
en base a otras respuestas, esta es mi implementación actual, que recupera archivos xml anidados en un directorio raíz:
files = []
for root, dirnames, filenames in os.walk(myDir):
files.extend(glob.glob(root + "/*.xml"))
Realmente me estoy divirtiendo con python :)
os.walk
usar os.walk
para recopilar nombres de archivos que coincidan con sus criterios. Por ejemplo:
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))
Python 3.5+
A partir de la versión 3.5 de Python, el módulo glob
admite la directiva "**"
(que se analiza solo si se pasa el indicador recursive
):
import glob
for filename in glob.iglob(''src/**/*.c'', recursive=True):
print(filename)
Si necesita una lista, solo use glob.glob
lugar de glob.iglob
.
Para los casos en que los archivos coincidentes comienzan con un punto (.); como archivos en el directorio actual o archivos ocultos en el sistema basado en Unix, use la solución os.walk
continuación.
Python 2.2 a 3.4
Para versiones anteriores de Python, comenzando con Python 2.2, use os.walk
para recorrer un directorio de forma recursiva y fnmatch.filter
para que coincida con una expresión simple:
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))
Python 2.1 y anteriores
Incluso para versiones antiguas de Python, use glob.glob
contra cada nombre de archivo en lugar de fnmatch.filter
.
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
te da exactamente los mismos patrones que glob
, por lo que este es realmente un excelente reemplazo para glob.glob
con una semántica muy cercana. Una versión iterativa (por ejemplo, un generador), glob.iglob
, un reemplazo para glob.iglob
, es una adaptación trivial (solo yield
los resultados intermedios a medida que glob.iglob
, en lugar de extend
una lista de resultados única para devolver al final).
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)