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?
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')]
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).
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 .
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.
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.
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")
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")
Es gibt viel Verwirrung in diesem Thema. Lassen Sie mich sehen, ob ich es klären kann (Python 3.7):
glob.glob('*.txt') :
stimmt mit allen Dateien überein, die im aktuellen Verzeichnis mit '.txt' endenglob.glob('*/*.txt') :
wie 1glob.glob('**/*.txt') :
stimmt mit allen Dateien überein, die mit '.txt' in den unmittelbaren Unterverzeichnissen enden , jedoch nicht im aktuellen Verzeichnisglob.glob('*.txt',recursive=True) :
wie 1glob.glob('*/*.txt',recursive=True) :
wie 3glob.glob('**/*.txt',recursive=True):
stimmt mit allen Dateien überein, die im aktuellen Verzeichnis und in allen Unterverzeichnissen mit '.txt' endenDaher ist es am besten, immer recursive=True.
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\\**\\**")
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.