Wie man mit os.walk in Python Verzeichnisse rekursiv durchsucht

Die os.walk-Funktion in Python ist ein leistungsstarkes Werkzeug, mit dem Verzeichnisse und deren Inhalte rekursiv durchsucht werden können. Mit dieser Funktion können alle Unterverzeichnisse und Dateien eines angegebenen Verzeichnisses effizient abgerufen werden. In diesem Artikel erklären wir die grundlegende Verwendung von os.walk sowie praktische Anwendungsbeispiele. Dadurch werden Sie in der Lage sein, Aufgaben, die Verzeichnisoperationen beinhalten, viel effizienter zu erledigen.

Inhaltsverzeichnis

Was ist os.walk?


os.walk ist eine Funktion im Python-Standardmodul os, mit der ein angegebenes Verzeichnis rekursiv durchsucht und eine Liste der Dateien und Unterverzeichnisse im Verzeichnis erzeugt wird. Durch die Verwendung dieser Funktion können komplexe Verzeichnisstrukturen einfach durchsucht werden, und sie ist sehr nützlich, um eine Liste von Dateien und Ordnern zu erhalten.

Wie funktioniert os.walk?


os.walk arbeitet als Generator und gibt ein Tupel mit den folgenden drei Elementen zurück.

  1. Verzeichnispfad (dirpath)
    Der Pfad des aktuell durchsuchten Verzeichnisses.
  2. Liste der Unterverzeichnisse (dirnames)
    Eine Liste der Unterverzeichnisse im aktuellen Verzeichnis.
  3. Liste der Dateien (filenames)
    Eine Liste der Dateinamen im aktuellen Verzeichnis.

Eigenschaften

  • Rekursive Suche: Unterverzeichnisse des angegebenen Verzeichnisses werden automatisch durchsucht.
  • Reihenfolge: Es kann eingestellt werden, ob die Verzeichnishierarchie von oben nach unten oder von unten nach oben verarbeitet werden soll (topdown=True/False).
  • Effizienz: Die benötigten Informationen werden direkt bei Bedarf generiert, was den Speicherverbrauch optimiert.

Anwendungen

  • Suche nach Dateinamen
  • Erstellung einer Liste von Dateien mit bestimmten Dateiendungen
  • Berechnung der Größe von Unterverzeichnissen
  • Automatisierung von Backup- oder Verschiebungsaufgaben

Grundlegende Verwendung

Mit os.walk können Sie Dateien und Ordner im angegebenen Verzeichnis einfach abrufen. Nachfolgend finden Sie ein einfaches Beispiel für den Code.

Code-Beispiel

import os

# Verzeichnis angeben
target_directory = "/path/to/your/directory"

# os.walk verwenden, um das Verzeichnis zu durchsuchen
for dirpath, dirnames, filenames in os.walk(target_directory):
    print(f"Current Path: {dirpath}")
    print(f"Directories: {dirnames}")
    print(f"Files: {filenames}")
    print("-" * 40)

Beispielausgabe


Angenommene Verzeichnisstruktur:

/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│   └── file3.txt
└── subdir2
    └── file4.txt

Wenn Sie os.walk ausführen, erhalten Sie folgende Ausgabe:

Current Path: /path/to/your/directory
Directories: ['subdir1', 'subdir2']
Files: ['file1.txt', 'file2.txt']
----------------------------------------
Current Path: /path/to/your/directory/subdir1
Directories: []
Files: ['file3.txt']
----------------------------------------
Current Path: /path/to/your/directory/subdir2
Directories: []
Files: ['file4.txt']
----------------------------------------

Erklärung

  • dirpath: Der Pfad des aktuell durchsuchten Verzeichnisses.
  • dirnames: Eine Liste der Unterverzeichnisse im aktuellen Verzeichnis.
  • filenames: Eine Liste der Dateien im aktuellen Verzeichnis.

Wichtige Hinweise


Wenn das angegebene Verzeichnis nicht existiert, wirft os.walk einen Fehler. Es ist daher sicherer, vor der Verwendung die Existenz des Verzeichnisses zu überprüfen.

Verarbeitung von Dateien und Verzeichnissen

Mit os.walk können Sie Dateien und Ordner effizient kategorisieren. Wenn Sie verschiedene Verarbeitungen für jedes benötigen, können Sie dies leicht durch Hinzufügen von Verzweigungslogik umsetzen.

Code-Beispiel


Nachfolgend ein Beispiel, wie man unterschiedliche Verarbeitungen für Dateien und Verzeichnisse anwendet:

import os

# Verzeichnis angeben
target_directory = "/path/to/your/directory"

# Verzeichnis durchsuchen und Verarbeitungen durchführen
for dirpath, dirnames, filenames in os.walk(target_directory):
    # Verzeichnisse verarbeiten
    for dirname in dirnames:
        subdir_path = os.path.join(dirpath, dirname)
        print(f"Directory: {subdir_path}")

    # Dateien verarbeiten
    for filename in filenames:
        file_path = os.path.join(dirpath, filename)
        print(f"File: {file_path}")

Beispielausgabe


Verzeichnisstruktur:

/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│   └── file3.txt
└── subdir2
    └── file4.txt

Die Ausgabe wird wie folgt aussehen:

Directory: /path/to/your/directory/subdir1
Directory: /path/to/your/directory/subdir2
File: /path/to/your/directory/file1.txt
File: /path/to/your/directory/file2.txt
File: /path/to/your/directory/subdir1/file3.txt
File: /path/to/your/directory/subdir2/file4.txt

Erklärung des Codes

  • os.path.join: Kombiniert dirpath mit dirname oder filename, um den vollständigen Pfad zu erzeugen.
  • Verzeichnisverarbeitung (for dirname in dirnames): Sie können spezifische Operationen für Verzeichnisse anwenden (z. B. Ermitteln des Erstellungsdatums eines Verzeichnisses).
  • Dateiverarbeitung (for filename in filenames): Sie können spezifische Operationen für Dateien anwenden (z. B. Ermitteln der Dateigröße).

Praktisches Beispiel

  • Erstellen und Verwalten einer Liste von Unterverzeichnissen.
  • Extrahieren und Verarbeiten von Dateien, die einem bestimmten Namensmuster entsprechen.
  • Filtern von Dateien basierend auf Größe oder Erstellungsdatum.

Suche nach Dateien mit einer bestimmten Erweiterung

Mit os.walk können Sie auch Dateien mit bestimmten Erweiterungen einfach suchen. Dies ist besonders nützlich, wenn Sie Dateien mit einer bestimmten Endung wie .txt oder .jpg extrahieren möchten.

Code-Beispiel


Hier ist ein Beispiel, wie man Dateien mit der Erweiterung .txt findet und deren Pfad ausgibt:

import os

# Verzeichnis angeben
target_directory = "/path/to/your/directory"

# Die zu suchende Erweiterung angeben
target_extension = ".txt"

# Dateien mit der angegebenen Erweiterung suchen
for dirpath, dirnames, filenames in os.walk(target_directory):
    for filename in filenames:
        if filename.endswith(target_extension):
            file_path = os.path.join(dirpath, filename)
            print(f"Found: {file_path}")

Beispielausgabe


Angenommene Verzeichnisstruktur:

/path/to/your/directory
├── file1.txt
├── file2.doc
├── subdir1
│   └── notes.txt
└── subdir2
    └── image.png

Die Ausgabe wird wie folgt aussehen:

Found: /path/to/your/directory/file1.txt
Found: /path/to/your/directory/subdir1/notes.txt

Erklärung des Codes

  • filename.endswith(target_extension): Gibt True zurück, wenn der Dateiname mit der angegebenen Erweiterung endet. Dadurch können Sie nach bestimmten Dateiformaten filtern.
  • os.path.join: Wird verwendet, um den vollständigen Pfad der Datei zu erzeugen.

Suche nach mehreren Erweiterungen


Um nach mehreren Erweiterungen zu suchen, ändern Sie einfach die Bedingungen.

# Zu suchende Erweiterungen in einer Liste angeben
target_extensions = [".txt", ".doc"]

for dirpath, dirnames, filenames in os.walk(target_directory):
    for filename in filenames:
        if filename.endswith(tuple(target_extensions)):
            file_path = os.path.join(dirpath, filename)
            print(f"Found: {file_path}")

Praktisches Beispiel

  • Liste der Quellcodedateien eines Projekts erhalten (z. B. .py Dateien).
  • Suche nach bestimmten Bildformaten (z. B. .jpg oder .png) und verarbeite diese in einem Rutsch.
  • Erstellen von Dateistatistiken nach Erweiterung.

Verzeichnisdurchsuchung mit Tiefenbegrenzung

os.walk durchsucht standardmäßig alle Ebenen eines Verzeichnisses rekursiv. Es kann jedoch Situationen geben, in denen Sie die Durchsuchung auf eine bestimmte Tiefe begrenzen möchten. In solchen Fällen können Sie die aktuelle Tiefe verfolgen und die Verarbeitung einschränken.

Code-Beispiel


Hier ein Beispiel, wie man die Verzeichnistiefe auf 2 beschränkt:

import os

# Verzeichnis angeben
target_directory = "/path/to/your/directory"

# Maximale Suchtiefe festlegen
max_depth = 2

# Durchsuchung mit Tiefenbegrenzung
for dirpath, dirnames, filenames in os.walk(target_directory):
    # Berechne die aktuelle Tiefe
    current_depth = dirpath.count(os.sep) - target_directory.count(os.sep) + 1

    if current_depth > max_depth:
        # Wenn die Tiefe überschritten wird, überspringe die Unterverzeichnisse
        del dirnames[:]  # Lösche dirnames, um Unterverzeichnisse zu ignorieren
        continue

    print(f"Depth {current_depth}: {dirpath}")
    print(f"Directories: {dirnames}")
    print(f"Files: {filenames}")
    print("-" * 40)

Beispielausgabe


Verzeichnisstruktur:

/path/to/your/directory
├── file1.txt
├── subdir1
│   ├── file2.txt
│   └── subsubdir1
│       └── file3.txt
└── subdir2
    └── file4.txt

Mit einer Begrenzung auf Tiefe 2 erhält man folgende Ausgabe:

Depth 1: /path/to/your/directory
Directories: ['subdir1', 'subdir2']
Files: ['file1.txt']
----------------------------------------
Depth 2: /path/to/your/directory/subdir1
Directories: ['subsubdir1']
Files: ['file2.txt']
----------------------------------------
Depth 2: /path/to/your/directory/subdir2
Directories: []
Files: ['file4.txt']
----------------------------------------

Erklärung des Codes

  • os.sep: Ruft das betriebssystemabhängige Verzeichnistrennzeichen ab (auf Windows ist es \\, auf Unix /).
  • dirpath.count(os.sep): Zählt die Anzahl der Trennzeichen im Verzeichnispfad und berechnet auf dieser Grundlage die Tiefe.
  • del dirnames[:]: Leert die Liste der Unterverzeichnisse und überspringt somit alle weiteren Verzeichnisebenen.

Praktische Anwendungen

  • Durchsuchen nur der oberen Verzeichnisebenen in großen Projekten.
  • Anzeige eines Teils des Verzeichnisbaums mit einer Begrenzung der Tiefe.
  • Reduzierung der Last bei Festplattenoperationen durch eingeschränkte Suche.

Ignorieren von versteckten Dateien und Ordnern

Wenn Sie Verzeichnisse durchsuchen, möchten Sie möglicherweise versteckte Dateien oder Ordner (die normalerweise mit einem Punkt . beginnen) ignorieren. Mit os.walk können Sie diese Elemente filtern, um eine effizientere Verarbeitung zu ermöglichen.

Code-Beispiel


Hier ein Beispiel, wie man versteckte Dateien und Ordner bei der Durchsuchung ignoriert:

import os

# Verzeichnis angeben
target_directory = "/path/to/your/directory"

# Durchsuchung mit Ignorierung versteckter Dateien und Ordner
for dirpath, dirnames, filenames in os.walk(target_directory):
    # Versteckte Ordner ignorieren
    dirnames[:] = [d for d in dirnames if not d.startswith(".")]

    # Versteckte Dateien ignorieren
    visible_files = [f for f in filenames if not f.startswith(".")]

    print(f"Current Path: {dirpath}")
    print(f"Directories: {dirnames}")
    print(f"Files: {visible_files}")
    print("-" * 40)

Beispielausgabe


Angenommene Verzeichnisstruktur:

/path/to/your/directory
├── file1.txt
├── .hidden_file.txt
├── subdir1
│   ├── file2.txt
│   └── .hidden_folder
│       └── file3.txt
└── subdir2
    └── file4.txt

Wenn versteckte Dateien und Ordner ignoriert werden, sieht die Ausgabe wie folgt aus:

Current Path: /path/to/your/directory
Directories: ['subdir1', 'subdir2']
Files: ['file1.txt']
----------------------------------------
Current Path: /path/to/your/directory/subdir1
Directories: []
Files: ['file2.txt']
----------------------------------------
Current Path: /path/to/your/directory/subdir2
Directories: []
Files: ['file4.txt']
----------------------------------------

Erklärung des Codes

  • Versteckte Ordner ignorieren (dirnames[:] = ...): Überschreibt die dirnames Liste und schließt Ordner aus, deren Namen mit einem Punkt (.) beginnen. Diese Operation stellt sicher, dass auch alle darunter liegenden Ebenen nicht durchsucht werden.
  • Versteckte Dateien ignorieren ([f for f in filenames ...]): Verwendet Listenverständnis, um Dateien auszuschließen, deren Namen mit einem Punkt (.) beginnen.

Wichtige Hinweise

  • Wenn Dateien oder Ordner als Systemdateien „versteckt“ markiert sind (insbesondere unter Windows), kann dieser Code sie nicht erkennen. In diesem Fall müssen zusätzliche Module wie ctypes verwendet werden.

Praktische Anwendungen

  • Das Ausschließen von Konfigurationsdateien mit verstecktem Status (z. B. .gitignore oder .env).
  • Erstellen einer Verzeichnisübersicht, die nicht versteckte Elemente enthält.
  • Bereinigung großer Datensätze durch Ausschluss versteckter Elemente.

Praktisches Beispiel: Berechnung der Verzeichnisgröße

Mit os.walk können Sie die Größe aller Dateien in einem Verzeichnis summieren und so die Gesamtgröße des Verzeichnisses berechnen. Dies ist nützlich, wenn Sie herausfinden möchten, wie viel Speicherplatz ein bestimmtes Verzeichnis beansprucht.

Code-Beispiel


Hier ein Beispiel, wie man die Verzeichnisgröße berechnet:

import os

# Verzeichnis angeben
target_directory = "/path/to/your/directory"

def calculate_directory_size(directory):
    total_size = 0
    # Verzeichnis durchsuchen
    for dirpath, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            file_path = os.path.join(dirpath, filename)
            try:
                # Dateigröße ermitteln und addieren
                total_size += os.path.getsize(file_path)
            except FileNotFoundError:
                # Fehlerbehandlung, falls die Datei gelöscht wurde
                pass
    return total_size

# Verzeichnisgröße berechnen
directory_size = calculate_directory_size(target_directory)

# Ergebnis ausgeben (in Byte und MB)
print(f"Directory Size: {directory_size} bytes")
print(f"Directory Size: {directory_size / (1024 ** 2):.2f} MB")

Beispielausgabe


Verzeichnisstruktur:

/path/to/your/directory
├── file1.txt (500 bytes)
├── subdir1
│   ├── file2.txt (1500 bytes)
│   └── file3.txt (3000 bytes)
└── subdir2
    └── file4.txt (2000 bytes)

Das Ergebnis sieht wie folgt aus:

Directory Size: 7000 bytes  
Directory Size: 0.01 MB  

Erklärung des Codes

  • os.path.getsize(file_path): Ermittelt die Dateigröße in Byte.
  • Fehlerbehandlung: Wenn eine Datei während der Ausführung gelöscht wird oder nicht zugänglich ist, fängt der Code die FileNotFoundError-Ausnahme ab.
  • Einheitenumrechnung: Der Code konvertiert die Größe von Byte in eine benutzerfreundlichere Einheit wie KB oder MB.

Praktische Anwendung: Berechnung der Dateigröße nach Erweiterung


Um die Gesamtgröße von Dateien mit einer bestimmten Erweiterung zu berechnen, ändern Sie den Code wie folgt:

def calculate_size_by_extension(directory, extension):
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            if filename.endswith(extension):
                file_path = os.path.join(dirpath, filename)
                try:
                    total_size += os.path.getsize(file_path)
                except FileNotFoundError:
                    pass
    return total_size

# Beispiel: Berechnung der Gesamtgröße von .txt-Dateien
txt_size = calculate_size_by_extension(target_directory, ".txt")
print(f".txt Files Size: {txt_size} bytes")

Praktische Anwendung

  • Überwachung der Festplattennutzung auf Servern oder in Cloud-Speichern.
  • Ermitteln des Ressourcenverbrauchs in bestimmten Projektordnern.
  • Unterstützung bei der Bereinigung von Festplatten bei Speicherplatzmangel.

Praktische Anwendung: Backup aller Dateien

Mit os.walk können Sie alle Dateien im Verzeichnis rekursiv durchsuchen und an einen angegebenen Backup-Ordner kopieren, wodurch ein vollständiges Backup des Verzeichnisses erstellt wird. Diese Methode ist besonders nützlich, um Daten sicher zu kopieren, während die Ordnerstruktur beibehalten wird.

Code-Beispiel


Hier ist ein Beispiel, wie man Dateien in ein Backup-Verzeichnis kopiert:

import os
import shutil

# Ursprungs- und Backup-Verzeichnis angeben
source_directory = "/path/to/your/source_directory"
backup_directory = "/path/to/your/backup_directory"

def backup_files(source, backup):
    for dirpath, dirnames, filenames in os.walk(source):
        # Berechne den Pfad im Backup-Verzeichnis
        relative_path = os.path.relpath(dirpath, source)
        backup_path = os.path.join(backup, relative_path)

        # Erstelle das Backup-Verzeichnis
        os.makedirs(backup_path, exist_ok=True)

        for filename in filenames:
            source_file = os.path.join(dirpath, filename)
            backup_file = os.path.join(backup_path, filename)

            try:
                # Kopiere die Datei
                shutil.copy2(source_file, backup_file)
                print(f"Copied: {source_file} -> {backup_file}")
            except Exception as e:
                print(f"Failed to copy {source_file}: {e}")

# Backup ausführen
backup_files(source_directory, backup_directory)

Beispielausgabe


Verzeichnisstruktur:

/path/to/your/source_directory
├── file1.txt
├── subdir1
│   ├── file2.txt
│   └── file3.txt
└── subdir2
    └── file4.txt

Das Backup-Verzeichnis sieht danach folgendermaßen aus:

/path/to/your/backup_directory
├── file1.txt
├── subdir1
│   ├── file2.txt
│   └── file3.txt
└── subdir2
    └── file4.txt

Erklärung des Codes

  • os.makedirs(backup_path, exist_ok=True): Erstellt das Backup-Verzeichnis rekursiv. Mit exist_ok=True wird kein Fehler erzeugt, wenn das Verzeichnis bereits existiert.
  • os.path.relpath(dirpath, source): Ermittelt den relativen Pfad von der Quelle, um das Backup-Verzeichnis entsprechend zu erstellen.
  • shutil.copy2(source_file, backup_file): Kopiert nicht nur den Inhalt der Datei, sondern auch deren Metadaten (z. B. Zeitstempel).

Wichtige Hinweise

  1. Symbolische Links: shutil.copy2 kopiert symbolische Links als normale Dateien. Wenn Sie die Links beibehalten möchten, ist eine separate Behandlung erforderlich.
  2. Festplattenkapazität: Stellen Sie sicher, dass im Ziel-Backup-Verzeichnis genügend Speicherplatz vorhanden ist.
  3. Zugriffsrechte: Sie müssen über die notwendigen Zugriffsrechte für die Quell-Dateien verfügen.

Praktische Anwendungen

  • Backup nur bestimmter Dateitypen: Fügen Sie z. B. die Bedingung if filename.endswith(".txt") hinzu.
  • Protokollierung des Backups: Schreiben Sie die kopierten Dateien in eine Logdatei.
  • Differentielles Backup: Vergleichen Sie die Zeitstempel oder Hash-Werte von Dateien und kopieren Sie nur geänderte Dateien.

Zusammenfassung

In diesem Artikel haben wir erklärt, wie man mit os.walk in Python Verzeichnisse rekursiv durchsucht und zahlreiche Anwendungsbeispiele gezeigt. os.walk ist ein leistungsstarkes Werkzeug, um Dateien und Ordner effizient zu durchsuchen und verschiedene Operationen durchzuführen.

Wir haben die grundlegende Nutzung, das Filtern nach bestimmten Bedingungen, die Begrenzung der Verzeichnistiefe, das Ausschließen versteckter Dateien, die Berechnung der Verzeichnisgröße und die Implementierung eines Backup-Kopierverfahrens behandelt.

Nutzen Sie die Flexibilität von os.walk, um Aufgaben mit Verzeichnissen zu automatisieren und Ihre Arbeitsweise erheblich zu verbessern. Testen Sie es in Ihren eigenen Projekten!

Inhaltsverzeichnis