it-swarm.com.de

Mit einem Glob () rekursiv nach Dateien in Python suchen?

Das ist was ich habe:

glob(os.path.join('src','*.c'))

aber ich möchte die Unterordner von src durchsuchen. So etwas würde funktionieren:

glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))

Dies ist jedoch offensichtlich begrenzt und klobig.

564
Ben Gartner

Python 3.5+

Ab der Python-Version 3.5 unterstützt das Modul glob die "**"-Direktive (die nur analysiert wird, wenn Sie das Flag recursive übergeben):

import glob

for filename in glob.iglob('src/**/*.c', recursive=True):
    print(filename)

Wenn Sie eine Liste benötigen, verwenden Sie einfach glob.glob anstelle von glob.iglob .

Für Fälle, in denen übereinstimmende Dateien mit einem Punkt beginnen (.); Verwenden Sie wie bei Dateien im aktuellen Verzeichnis oder versteckten Dateien auf Unix-basierten Systemen die Lösung os.walk unten.

Python 2.2 bis 3.4

Bei älteren Python-Versionen, beginnend mit Python 2.2, verwenden Sie os.walk , um ein Verzeichnis rekursiv zu durchsuchen, und fnmatch.filter , um einen einfachen Ausdruck zu finden:

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 und früher

Für noch ältere Python-Versionen verwenden Sie glob.glob anstelle jedes Dateinamens anstelle von fnmatch.filter .

1083
Johan Dahlin

Ähnlich wie bei anderen Lösungen, jedoch mit fnmatch.fnmatch anstelle von glob, da os.walk bereits die Dateinamen aufführt:

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

Wenn Sie einen Generator verwenden, können Sie auch jede Datei so verarbeiten, wie sie gefunden wurde, anstatt alle Dateien und dann zu finden.

102
Bruno Oliveira

Ich habe das glob-Modul so geändert, dass es ** für rekursives Globbing unterstützt, z. B .:

>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')

https://github.com/miracle2k/python-glob2/

Nützlich, wenn Sie Ihren Benutzern die Möglichkeit geben möchten, die ** Syntax zu verwenden, und daher ist os.walk () alleine nicht gut genug.

56
miracle2k

Ab Python 3.4 kann man die glob() -Methode einer der Path-Klassen im neuen pathlib - Modul verwenden, das **-Platzhalter unterstützt. Zum Beispiel:

from pathlib import Path

for file_path in Path('src').glob('**/*.c'):
    print(file_path) # do whatever you need with these files

Update: Ab Python 3.5 wird dieselbe Syntax auch von glob.glob() unterstützt.

49
taleinat
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 liefert genau die gleichen Muster wie glob , daher ist dies wirklich ein hervorragender Ersatz für glob.glob mit sehr enger Semantik. Eine iterative Version (z. B. ein Generator), IOW, ein Ersatz für glob.iglob, ist eine triviale Anpassung (lediglich yield die Zwischenergebnisse, während Sie fortfahren, anstatt extending eine einzelne Ergebnisliste am Ende zurückzugeben).

39
Alex Martelli

Verwenden Sie os.walk, um Dateinamen zu sammeln, die Ihren Kriterien entsprechen. Zum Beispiel:

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))
20
Geoff Reedy

Hier ist eine Lösung mit verschachtelten Listenübergängen, os.walk und einfachem Suffix-Matching anstelle von 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')]

Es kann zu einem Einzeiler komprimiert werden:

import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')]

oder verallgemeinert als Funktion:

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

Wenn Sie vollständige glob-Stilmuster benötigen, können Sie den Beispielen von Alex und Bruno folgen und fnmatch verwenden:

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')
14
akaihola

Vor kurzem musste ich meine Bilder mit der Erweiterung .jpg wiederherstellen. Ich habe photorec ausgeführt und 4579 Verzeichnisse innerhalb von 2,2 Millionen Dateien wiederhergestellt, die eine enorme Vielfalt an Erweiterungen haben.

#!/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)
5
Mustafa Çetin

Johan und Bruno bieten ausgezeichnete Lösungen für die genannten Mindestanforderungen. Ich habe gerade Formic veröffentlicht, das Ant FileSet und Globs implementiert , das diese und kompliziertere Szenarien verarbeiten kann. Eine Implementierung Ihrer Anforderung ist:

import formic
fileset = formic.FileSet(include="/src/**/*.c")
for file_name in fileset.qualified_files():
    print file_name
5
Andrew Alcock

basierend auf anderen Antworten ist dies meine derzeitige Implementierung, die verschachtelte XML-Dateien in einem Stammverzeichnis abruft:

files = []
for root, dirnames, filenames in os.walk(myDir):
    files.extend(glob.glob(root + "/*.xml"))

Ich habe wirklich Spaß mit Python :)

5
daveoncode

Eine andere Möglichkeit, dies nur mit dem Glob-Modul zu tun. Keimen Sie einfach die rglob-Methode mit einem Ausgangsverzeichnis und einem passenden Muster, und es wird eine Liste der übereinstimmenden Dateinamen zurückgegeben.

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
3
chris-piekarski

Zusätzlich zu den vorgeschlagenen Antworten können Sie dies mit etwas Zaubern für das Generieren und Listenverständnis tun:

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)

Neben dem Einfügen in eine Zeile und dem Vermeiden unnötiger Listen im Speicher hat dies auch den Nebeneffekt von Nice, dass Sie ihn ähnlich wie den Operator ** verwenden können, z. B. können Sie os.path.join(root, 'some/path/*.c') verwenden, um alle .c-Dateien zu erhalten alle Unterverzeichnisse von src, die diese Struktur haben.

2
fxx

Gerade gemacht .. es werden Dateien und Verzeichnisse auf hierarchische Weise gedruckt

Aber ich habe weder fnmatch noch zu Fuß benutzt

#!/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)
2
Shaurya Gupta

Betrachten Sie pathlib.rglob() .

Dies ist wie der Aufruf von Path.glob(), wobei "**/" vor dem angegebenen relativen Muster hinzugefügt wird:

import pathlib


for p in pathlib.Path("src").rglob("*.c"):
    print(p)

Siehe auch @ taleinats verwandtes post hier und ein früheres post anderswo.

1
pylang

Dieser verwendet fnmatch oder regulären Ausdruck:

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 __== '__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')])
1
hipertracker

Hier ist meine Lösung, die das Listenverständnis für die Suche nach multiple Dateiendungen rekursiv in einem Verzeichnis und allen Unterverzeichnissen verwendet:

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
1
sackpower

Vereinfachte Version von Johan Dahlins Antwort ohne 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']
1
flowfree

Für python> = .5 können Sie **, recursive=True verwenden:

import glob
for x in glob.glob('path/**/*.c', recursive=True):
    print(x)

Demo


Wenn rekursiv wahr ist, entspricht das Muster ** allen Dateien und null oder mehr directories und subdirectories. Wenn dem Muster ein os.sep folgt, stimmen nur Verzeichnisse und subdirectories überein.

1
Pedro Lobito

Oder mit einem Listenverständnis:

 >>> 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") ] 
1
xtofl

Hier ist eine Lösung, bei der das Muster mit dem vollständigen Pfad und nicht nur mit dem Basisdateinamen abgeglichen wird.

Es verwendet fnmatch.translate , um ein Muster im Glob-Stil in einen regulären Ausdruck zu konvertieren, der dann mit dem vollständigen Pfad jeder gefundenen Datei abgeglichen wird, während das Verzeichnis durchsucht wird.

re.IGNORECASE ist optional, aber unter Windows wünschenswert, da das Dateisystem selbst nicht zwischen Groß- und Kleinschreibung unterscheidet. (Ich habe mir nicht die Mühe gemacht, den Regex zu kompilieren, da die Dokumente darauf hinweisen, dass er intern zwischengespeichert werden sollte.)

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
0
yoyo

Für python 3.5 und höher

file_names_array = glob.glob('src/*.c', recursive=True)

Bearbeiten: Als @NeStack geführt, wenn oben für Sie nicht funktioniert, versuchen Sie es bitte

file_names_array = glob.glob('src/**.c', recursive=True)

weiter könnten Sie brauchen

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'
0
Sami
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)
0
serega386

Ich habe die oberste Antwort in diesem Beitrag geändert. Vor kurzem habe ich dieses Skript erstellt, das alle Dateien in einem bestimmten Verzeichnis (searchdir) und die darunter liegenden Unterverzeichnisse durchläuft ... und den Dateinamen, das Stammverzeichnis, das Änderungsdatum/Erstellungsdatum und Größe.

Hoffe, das hilft jemandem ... und sie können das Verzeichnis abrufen und Dateiinformationen abrufen.

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))
0
ihightower

Ich brauchte eine Lösung für python 2.x, die fast für große Verzeichnisse unterstützt.
Ich endete damit:

import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", Shell=True)
for foundfile in foundfiles.splitlines():
    print foundfile

Beachten Sie, dass Sie möglicherweise eine Ausnahmebehandlung benötigen, falls ls keine übereinstimmende Datei findet.

0
Roman