it-swarm.com.de

Wie kann ich Unterordner mit dem glob.glob-Modul durchsuchen?

Ich möchte eine Reihe von Unterordnern in einem Ordner öffnen, einige Textdateien finden und einige Zeilen der Textdateien drucken. Ich benutze das:

configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt')

Dies kann jedoch nicht auch auf die Unterordner zugreifen. Weiß jemand, wie ich denselben Befehl auch für den Zugriff auf Unterordner verwenden kann?

86
UserYmY

In Python 3.5 und neuer verwenden Sie die neue rekursive Funktion **/:

configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True)

Wenn recursive gesetzt ist, entspricht ** Gefolgt von einem Pfadtrennzeichen 0 oder mehr Unterverzeichnissen.

In früheren Versionen von Python) kann glob.glob() Dateien in Unterverzeichnissen nicht rekursiv auflisten.

In diesem Fall würde ich stattdessen os.walk() in Kombination mit fnmatch.filter() verwenden:

import os
import fnmatch

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in fnmatch.filter(files, '*.txt')]

Dadurch werden Ihre Verzeichnisse rekursiv durchsucht und alle absoluten Pfadnamen werden auf die entsprechenden .txt - Dateien zurückgesetzt. In diesem speziellen Fall, in dem die Funktion fnmatch.filter() zu viel des Guten ist, können Sie auch einen Test .endswith() verwenden:

import os

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in files if f.endswith('.txt')]
129
Martijn Pieters

So suchen Sie Dateien in unmittelbaren Unterverzeichnissen:

configfiles = glob.glob(r'C:\Users\sam\Desktop\*\*.txt')

Für eine rekursive Version, die alle Unterverzeichnisse durchläuft, können Sie ** Verwenden und recursive=True Übergeben seit Python 3.5 :

configfiles = glob.glob(r'C:\Users\sam\Desktop\**\*.txt', recursive=True)

Beide Funktionsaufrufe geben Listen zurück. Sie können glob.iglob() verwenden, um Pfade nacheinander zurückzugeben. Oder benutze pathlib :

from pathlib import Path

path = Path(r'C:\Users\sam\Desktop')
txt_files_only_subdirs = path.glob('*/*.txt')
txt_files_all_recursively = path.rglob('*.txt') # including the current dir

Beide Methoden geben Iteratoren zurück (Sie können Pfade einzeln abrufen).

18
jfs

Das glob2 -Paket unterstützt Platzhalter und ist relativ schnell

code = '''
import glob2
glob2.glob("files/*/**")
'''
timeit.timeit(code, number=1)

Auf meinem Laptop dauert es ungefähr 2 Sekunden, bis eine Übereinstimmung vorliegt > 60.000 Dateipfade .

17
megawac

Sie können Formic mit Python 2.6 verwenden

import formic
fileset = formic.FileSet(include="**/*.txt", directory="C:/Users/sam/Desktop/")

Offenlegung - Ich bin der Autor dieses Pakets.

8
Andrew Alcock

Hier ist eine angepasste Version, die glob.glob wie Funktionalität ohne glob2.

def find_files(directory, pattern='*'):
    if not os.path.exists(directory):
        raise ValueError("Directory not found {}".format(directory))

    matches = []
    for root, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            full_path = os.path.join(root, filename)
            if fnmatch.filter([full_path], pattern):
                matches.append(os.path.join(root, filename))
    return matches

Also, wenn Sie die folgende dir-Struktur haben

tests/files
├── a0
│   ├── a0.txt
│   ├── a0.yaml
│   └── b0
│       ├── b0.yaml
│       └── b00.yaml
└── a1

Sie können so etwas tun

files = utils.find_files('tests/files','**/b0/b*.yaml')
> ['tests/files/a0/b0/b0.yaml', 'tests/files/a0/b0/b00.yaml']

Ziemlich genaues fnmatch Muster-Matching für den gesamten Dateinamen selbst und nicht nur für den Dateinamen.

3
cevaris

Wenn Sie Python 3.4+ ausführen, können Sie das pathlib -Modul verwenden. Das Path.glob() Methode unterstützt die ** pattern, was "dieses Verzeichnis und alle Unterverzeichnisse rekursiv" bedeutet. Es wird ein Generator zurückgegeben, der Path Objekte für alle übereinstimmenden Dateien liefert.

from pathlib import Path
configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt")
2
Eugene Yarmash

configfiles = glob.glob('C:/Users/sam/Desktop/**/*.txt")

Funktioniert nicht in allen Fällen, sondern verwendet glob2

configfiles = glob2.glob('C:/Users/sam/Desktop/**/*.txt")
2
NILESH KUMAR

Es gibt viel Verwirrung in diesem Thema. Lassen Sie mich sehen, ob ich es klären kann (Python 3.7):

  1. glob.glob('*.txt') : stimmt mit allen Dateien überein, die im aktuellen Verzeichnis mit '.txt' enden
  2. glob.glob('*/*.txt') : wie 1
  3. glob.glob('**/*.txt') : stimmt mit allen Dateien überein, die mit '.txt' in den unmittelbaren Unterverzeichnissen enden , jedoch nicht im aktuellen Verzeichnis
  4. glob.glob('*.txt',recursive=True) : wie 1
  5. glob.glob('*/*.txt',recursive=True) : wie 3
  6. glob.glob('**/*.txt',recursive=True): stimmt mit allen Dateien überein, die im aktuellen Verzeichnis und in allen Unterverzeichnissen mit '.txt' enden

Daher ist es am besten, immer recursive=True.

2
germ

Wenn Sie das glob2-Paket installieren können ...

import glob2
filenames = glob2.glob("C:\\top_directory\\**\\*.ext")  # Where ext is a specific file extension
folders = glob2.glob("C:\\top_directory\\**\\")

Alle Dateinamen und Ordner:

all_ff = glob2.glob("C:\\top_directory\\**\\**")  
2
dreab

Wie Martijn betont hat, kann glob dies nur mit dem Operator ** Tun, der in Python 3.5 eingeführt wurde. Da das OP explizit nach dem glob-Modul gefragt hat, gibt das folgende einen Lazy zurück Bewertungsiterator, der sich ähnlich verhält

import os, glob, itertools

configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt'))
                         for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/'))

Beachten Sie jedoch, dass Sie bei diesem Ansatz nur einmal über configfiles iterieren können. Wenn Sie eine echte Liste von Konfigurationsdateien benötigen, die für mehrere Operationen verwendet werden können, müssen Sie diese explizit mit list(configfiles) erstellen.

0
fxx