Umgang mit Datei- und Verzeichnispfaden

Für eine eingehende Beschäftigung mit praktischen Dateisystemoperationen lesen Sie unseren Blogbeitrag: 10 Essential File System Operations Every Developer Should Know.

In Python gibt es zwei Hauptmodule, die sich mit der Pfadmanipulation befassen. Eines ist das Modul os.path und das andere ist das Modul pathlib.

Pathlib vs OS Module

pathlib bietet weitaus mehr Funktionalität als die oben genannten, wie z. B. das Abrufen des Dateinamens, das Abrufen der Dateierweiterung, das Lesen/Schreiben einer Datei ohne manuelles Öffnen usw. Sehen Sie sich die offizielle Dokumentation an, wenn Sie mehr erfahren möchten.

Linux- und Windows-Pfade

Unter Windows werden Pfade mit umgekehrten Schrägstrichen (\) als Trennzeichen zwischen Ordnernamen geschrieben. Auf Unix-basierten Betriebssystemen wie macOS, Linux und BSDs wird der Schrägstrich (/) als Pfadtrennzeichen verwendet. Das Verknüpfen von Pfaden kann ein Problem darstellen, wenn Ihr Code auf verschiedenen Plattformen funktionieren soll.

Glücklicherweise bietet das pathlib-Modul von Python eine einfache Möglichkeit, dies zu handhaben.

Verwendung von pathlib unter *nix:

# pathlib.Path: plattformübergreifende Pfadbehandlung
from pathlib import Path

print(Path('usr').joinpath('bin').joinpath('spam'))  # Pfadkomponenten verknüpfen
usr/bin/spam

pathlib bietet auch eine Abkürzung für joinpath mithilfe des /-Operators:

# Path operator (/): bequeme Möglichkeit, Pfade zu verknüpfen (plattformübergreifend)
from pathlib import Path

print(Path('usr') / 'bin' / 'spam')  # / Operator anstelle von joinpath() verwenden
usr/bin/spam

Beachten Sie, dass sich das Pfadtrennzeichen zwischen Windows und Unix-basierten Betriebssystemen unterscheidet. Deshalb sollten Sie pathlib verwenden, anstatt Zeichenketten zusammenzufügen, um Pfade zu verknüpfen.

Quiz

Melden Sie sich an, um dieses Quiz zu beantworten und Ihren Lernfortschritt zu verfolgen

What is the correct way to join paths using pathlib in Python?
A. Path('usr') + 'bin' + 'spam'
B. Path('usr') / 'bin' / 'spam'
C. Path('usr').join('bin').join('spam')
D. Path('usr/bin/spam')

Das Verknüpfen von Pfaden ist hilfreich, wenn Sie verschiedene Dateipfade unter demselben Verzeichnis erstellen müssen.

Verwendung von pathlib unter *nix:

# Path.home(): Benutzer-Home-Verzeichnis abrufen, mit Dateinamen kombinieren
my_files = ['accounts.txt', 'details.csv', 'invite.docx']
home = Path.home()  # Home-Verzeichnis-Pfad abrufen
for filename in my_files:
    print(home / filename)  # Home-Pfad mit jedem Dateinamen kombinieren
/home/labex/project/accounts.txt
/home/labex/project/details.csv
/home/labex/project/invite.docx

Erweitern des Benutzer-Home-Verzeichnisses

Verwendung von os.path.expanduser(), um ~ in das Home-Verzeichnis des Benutzers zu erweitern:

import os.path

# ~ in das Home-Verzeichnis des Benutzers erweitern
print(os.path.expanduser('~'))
/home/labex/project
# ~/Documents in den vollständigen Pfad erweitern
print(os.path.expanduser('~/Documents'))
/home/labex/project/Documents
# Funktioniert mit Pfaden, die ~ enthalten
print(os.path.expanduser('~/myfile.txt'))
/home/labex/project/myfile.txt

Das aktuelle Arbeitsverzeichnis

Sie können das aktuelle Arbeitsverzeichnis mit pathlib abrufen:

# Path.cwd(): aktuelles Arbeitsverzeichnis abrufen
from pathlib import Path

print(Path.cwd())  # Gibt das aktuelle Arbeitsverzeichnis als Path-Objekt zurück
/home/labex/project

Erstellen neuer Ordner

Verwendung von pathlib unter *nix:

from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/pathlib.py", line 1226, in mkdir
    self._accessor.mkdir(self, mode)
  File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped
    return strfunc(str(pathobj), *args)
FileNotFoundError: [Errno 2] No such file or directory: '/home/labex/project/delicious/walnut/waffles'

Oh nein, wir haben einen hässlichen Fehler bekommen! Der Grund ist, dass das Verzeichnis ‘delicious’ nicht existiert, sodass wir die Verzeichnisse ‘walnut’ und ‘waffles’ nicht darunter erstellen können. Um dies zu beheben, tun Sie Folgendes:

# mkdir(parents=True): Verzeichnis und alle übergeordneten Verzeichnisse erstellen, falls erforderlich
from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True)  # Verschachtelte Verzeichnisse erstellen

Und alles ist gut :)

Absolute vs. Relative Pfade

Es gibt zwei Möglichkeiten, einen Dateipfad anzugeben.

  • Ein absoluter Pfad, der immer mit dem Stammverzeichnis beginnt
  • Ein relativer Pfad, der sich auf das aktuelle Arbeitsverzeichnis des Programms bezieht

Es gibt auch die Ordner Punkt (.) und Punkt-Punkt (..). Dies sind keine echten Ordner, sondern spezielle Namen, die in einem Pfad verwendet werden können. Ein einzelner Punkt („Punkt“) für einen Ordnernamen ist eine Kurzform für „dieses Verzeichnis“. Zwei Punkte („Punkt-Punkt“) bedeuten „das übergeordnete Verzeichnis“.

Umgang mit absoluten Pfaden

Um zu sehen, ob ein Pfad ein absoluter Pfad ist, verwenden Sie pathlib:

from pathlib import Path
Path('/').is_absolute()
True
Path('..').is_absolute()
False
Quiz

Melden Sie sich an, um dieses Quiz zu beantworten und Ihren Lernfortschritt zu verfolgen

What does Path('/').is_absolute() return?
A. True
B. False
C. None
D. '/'

Sie können einen absoluten Pfad mit pathlib extrahieren:

from pathlib import Path
print(Path.cwd())
/home/labex/project
print(Path('..').resolve())
/home

Umgang mit relativen Pfaden

Sie können einen relativen Pfad von einem Startpfad zu einem anderen Pfad mit pathlib abrufen:

from pathlib import Path
print(Path('/etc/passwd').relative_to('/'))
etc/passwd

Pfad- und Dateigültigkeit

Überprüfen, ob eine Datei/ein Verzeichnis existiert

Verwendung von pathlib unter *nix:

from pathlib import Path

Path('.').exists()
True
Path('setup.py').exists()
True
Path('/etc').exists()
True
Path('nonexistentfile').exists()
False

Überprüfen, ob ein Pfad eine Datei ist

Verwendung von pathlib unter *nix:

from pathlib import Path

Path('setup.py').is_file()
True
Path('/home').is_file()
False
Path('nonexistentfile').is_file()
False
Quiz

Melden Sie sich an, um dieses Quiz zu beantworten und Ihren Lernfortschritt zu verfolgen

What will Path('setup.py').is_file() return if setup.py exists?
A. 'setup.py'
B. False
C. True
D. None

Überprüfen, ob ein Pfad ein Verzeichnis ist

Verwendung von pathlib unter *nix:

from pathlib import Path

Path('/').is_dir()
True
Path('setup.py').is_dir()
False
Path('/spam').is_dir()
False

Größe einer Datei in Bytes abrufen

Verwendung von pathlib unter *nix:

from pathlib import Path

stat = Path('/bin/python3.6').stat()
print(stat) # stat enthält auch einige andere Informationen über die Datei
os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0,
--snip--
st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276)
print(stat.st_size) # Größe in Bytes
10024

Verzeichnisse auflisten

Verzeichnisinhalte auflisten mit pathlib unter *nix:

from pathlib import Path

for f in Path('/usr/bin').iterdir():
    print(f)
...
/usr/bin/tiff2rgba
/usr/bin/iconv
/usr/bin/ldd
/usr/bin/cache_restore
/usr/bin/udiskie
/usr/bin/unix2dos
/usr/bin/t1reencode
/usr/bin/epstopdf
/usr/bin/idle3
...

Dateigrößen von Verzeichnissen

WARNUNG

Verzeichnisse selbst haben auch eine Größe! Sie sollten also mit den Methoden aus den oben genannten Abschnitten überprüfen, ob ein Pfad eine Datei oder ein Verzeichnis ist.

Verwendung von pathlib unter *nix:

from pathlib import Path

total_size = 0
for sub_path in Path('/usr/bin').iterdir():
    total_size += sub_path.stat().st_size

print(total_size)
1903178911

Dateien und Ordner kopieren

Das Modul shutil bietet Funktionen zum Kopieren von Dateien sowie ganzer Ordner.

import shutil

shutil.copy('/tmp/spam.txt', '/tmp/delicious')
/tmp/delicious/spam.txt
shutil.copy('/tmp/eggs.txt', '/tmp/delicious/eggs2.txt')
/tmp/delicious/eggs2.txt
Quiz

Melden Sie sich an, um dieses Quiz zu beantworten und Ihren Lernfortschritt zu verfolgen

Which function should you use to copy an entire directory tree including all subdirectories and files?
A. shutil.copy()
B. Path.copy()
C. os.copy()
D. shutil.copytree()

Während shutil.copy() eine einzelne Datei kopiert, kopiert shutil.copytree() einen gesamten Ordner und jeden darin enthaltenen Ordner und jede darin enthaltene Datei:

import shutil

shutil.copytree('/tmp/bacon', '/tmp/bacon_backup')
/tmp/bacon_backup

Verschieben und Umbenennen

import shutil

shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs/bacon.txt

Der Zielpfad kann auch einen Dateinamen angeben. Im folgenden Beispiel wird die Quelldatei verschoben und umbenannt:

shutil.move('/tmp/bacon.txt', '/tmp/eggs/new_bacon.txt')
/tmp/eggs/new_bacon.txt

Wenn es keinen eggs-Ordner gibt, benennt move() bacon.txt in eine Datei namens eggs um:

shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs

Löschen von Dateien und Ordnern

  • Der Aufruf von Path.unlink() löscht die Datei am Pfad.
  • Der Aufruf von Path.rmdir() löscht den Ordner am Pfad. Dieser Ordner muss leer von Dateien oder Ordnern sein.
  • Der Aufruf von shutil.rmtree(path) entfernt den Ordner am Pfad, und alle darin enthaltenen Dateien und Ordner werden ebenfalls gelöscht.
Quiz

Melden Sie sich an, um dieses Quiz zu beantworten und Ihren Lernfortschritt zu verfolgen

Which method can delete a non-empty directory and all its contents?
A. Path.rmdir()
B. shutil.rmtree()
C. Path.unlink()
D. os.remove()

Durchlaufen eines Verzeichnisbaums

Das Path-Objekt verfügt über eine rglob()-Methode, um rekursiv über Dateien und Verzeichnisse zu iterieren.

from pathlib import Path

p = Path('/tmp/delicious')
for i in p.rglob('*'):
    print(i)
/tmp/delicious/cats
/tmp/delicious/walnut
/tmp/delicious/spam.txt
/tmp/delicious/cats/catnames.txt
/tmp/delicious/cats/zophie.jpg
/tmp/delicious/walnut/waffles
/tmp/delicious/walnut/waffles/butter.txt