Dateien und Verzeichnisse¶
pathlib implementiert Pfadoperationen mithilfe von
pathlib.PurePath- und pathlib.Path-Objekten.
Die os- und os.path-Module hingegen bieten
Funktionen, die low-level mit str- und bytes arbeiten, was eher einem
prozeduralen Ansatz entspricht. Wir halten den objektorientierten Stil von
pathlib für besser lesbar und stellen ihn deswegen hier
ausführlicher vor.
Siehe auch
PEP 428: The pathlib module – object-oriented filesystem paths
Lesen und Schreiben von Dateien¶
In Python öffnet und lest ihr eine Datei, indem ihr die Funktion
pathlib.Path.open() und verschiedene eingebaute Leseoperationen
verwendet. pathlib.Path.open() öffnet die Datei, auf die der Pfad
verweist, wie es die integrierte Funktion open() tut. Das folgende
kurze Python-Programm liest eine Zeile aus einer Textdatei namens
myfile.txt in docs/save-data/ ein:
1>>> from pathlib import Path
2>>> p = Path("docs", "save-data", "myfile.txt")
3>>> f = p.open()
4>>> headline = f.readline()
- Zeile 2:
Die Argumente von
pathlib.Pathsind Pfadsegmente, entweder alsPosixPathoderWindowsPath. Im vorigen Beispiel öffnet ihr eine Datei, von der ihr annehmt, dass sie sich relativ zu eurem Aufruf imdocs/save-data/myfile.txtbefindet.Das folgende Beispiel öffnet eine Datei an einem absoluten Speicherort –
C:\My Documents\myfile.txt:2>>> p = Path("C:/", "Users", "Veit", "My Documents", "myfile.txt") 3>>> with p.open() as f: 4... f.readline() 5...
Bemerkung
In diesem Beispiel wird das Schlüsselwort
withverwendet, d.h., dass die Datei mit einem Kontextmanager geöffnet wird, der in Kontextmanagement mit with näher erläutert wird. Diese Art des Öffnens von Dateien verwaltet mögliche I/O-Fehler besser und sollte im Allgemeinen bevorzugt werden.- Zeile 3:
pathlib.Path.open()liest nichts aus der Datei, sondern gibt ein Datei-Objekt zurück, mit dem ihr auf die geöffnete Datei zugreifen könnt. Es behält den Überblick über eine Datei und darüber, wie viel von der Datei gelesen oder geschrieben wurde. Alle Dateieingaben in Python werden mit Dateiobjekten und nicht mit Dateinamen durchgeführt.- Zeile 4:
Der erste Aufruf von
readline()gibt die erste Zeile des Datei-Objekts zurück, also alles bis einschließlich des ersten Zeilenumbruchs oder die gesamte Datei, wenn es keinen Zeilenumbruch in der Datei gibt; der nächste Aufruf vonreadline()gibt die zweite Zeile zurück, wenn sie existiert usw. Wenn es nichts mehr zu lesen gibt, gibtreadline()einen leeren String zurück.
Dieses Verhalten von readline() macht es
einfach, z.B. die Anzahl der Zeilen in einer Datei zu
ermitteln:
>>> with p.open() as f:
... lc = 0
... while f.readline() != "":
... lc = lc + 1
... print(lc)
...
2
Ein kürzerer Weg, alle Zeilen zu zählen, gibt es mit der ebenfalls eingebauten
readlines()-Methode, die alle Zeilen
einer Datei liest und sie als Liste von Strings mit einen String pro Zeile
zurückgibt:
>>> with p.open() as f:
... print(len(f.readlines()))
...
2
Wenn ihr alle Zeilen einer großen Datei zählt, kann diese Methode jedoch dazu
führen, dass der Speicher vollläuft, weil die gesamte Datei auf einmal gelesen
wird. Es ist auch möglich, dass der Speicher mit readline() überläuft, wenn ihr versucht, eine Zeile aus
einer großen Datei zu lesen, die keine Zeilenumbruchzeichen enthält. Um mit
solchen Situationen besser umgehen zu können, haben beide Methoden ein
optionales Argument, das die Menge der zu einem Zeitpunkt gelesenen Daten
beeinflusst. Eine andere Möglichkeit, über alle Zeilen einer Datei zu iterieren,
besteht darin, das Dateiobjekt als Iterator in einer for-Schleife zu
behandeln:
>>> with p.open() as f:
... lc = 0
... for l in f:
... lc = lc + 1
... print(lc)
...
2
Diese Methode hat den Vorteil, dass die Zeilen je nach Bedarf in den Speicher eingelesen werden, so dass selbst bei großen Dateien kein Speicherplatzmangel zu befürchten ist. Der andere Vorteil dieser Methode ist, dass sie einfacher und lesbarer ist.
Ein mögliches Problem mit der Lesemethode kann jedoch entstehen, wenn auf
Windows- und macOS Übersetzungen im Textmodus erfolgen, wenn ihr den Befehl
open() im Textmodus verwenden, d.h. ohne ein b
anzuhängen. Im Textmodus wird auf macOS jedes \r in \n umgewandelt,
während unter Windows \r\n-Paare in \n umgewandelt werden. Ihr könnt die
Behandlung von Zeilenumbrüchen festlegen, indem ihr beim Öffnen der Datei den
Parameter newline verwendet und newline="\n", \r oder \r\n
angebt, wodurch nur diese Zeichenfolge als Zeilenumbruch verwendet wird:
>>> with p.open(newline="\r\n") as f:
... lc = 0
...
In diesem Beispiel wird nur \n als Zeilenumbruch gewertet. Wenn die Datei
jedoch im Binärmodus geöffnet wurde, ist der Parameter newline nicht
erforderlich, da alle Bytes genau so zurückgegeben werden, wie sie in der Datei
stehen.
pathlib.Path.read_text()gibt den dekodierten Inhalt der angegebenen Datei als Zeichenkette zurück:
>>> p.read_text() 'This is the first line of myfile.\nAnd this is another line.\n'
pathlib.Path.write_text()öffnet die angegebene Datei im Textmodus, schreibt Daten in sie und schließt die Datei:
>>> p.write_text("New content") 11 >>> p.read_text() 'New content'
Eine vorhandene Datei mit demselben Namen wird überschrieben.
Verzeichnisse lesen¶
pathlib.Path.iterdir()Wenn der Pfad auf ein Verzeichnis verweist, werden die Pfadobjekte des Verzeichnisinhalts zurückgegeben:
>>> p = Path("docs", "save-data") >>> for child in p.iterdir(): ... child ... PosixPath('docs/save-data/index.rst') PosixPath('docs/save-data/minidom_example.py') PosixPath('docs/save-data/pickle.rst') PosixPath('docs/save-data/xml.rst') PosixPath('docs/save-data/books.xml') PosixPath('docs/save-data/files.rst')
Die Kind-Objekte werden in beliebiger Reihenfolge zurückgegeben, und die
speziellen Einträge . und .. sind nicht enthalten. Wenn der Pfad kein
Verzeichnis oder anderweitig nicht zugänglich ist, wird ein
OSError ausgelöst.
pathlib.Path.glob()findet das angegebene relative Muster im Verzeichnis, das durch diesen Pfad dargestellt wird, und gibt alle übereinstimmenden Dateien aus:
>>> sorted(p.glob("*.rst")) [PosixPath('docs/save-data/files.rst'), PosixPath('docs/save-data/index.rst'), PosixPath('docs/save-data/pickle.rst'), PosixPath('docs/save-data/xml.rst')]
Siehe auch
pathlib.Path.rglob()findet das angegebene relative Muster rekursiv. Dies entspricht dem Aufruf mit
**/vor dem Muster.pathlib.Path.walk()generiert die Dateinamen in einer Verzeichnisstruktur, indem es die Struktur entweder von oben nach unten oder von unten nach oben durchläuft. Zurückgegeben wird ein 3-Tupel aus
(dirpath, dirnames, filenames).Bei der Standardeinstellung des optionalen Arguments
top_down=Truewird das Triple für ein Verzeichnis vor den Triples für seine Unterverzeichnisse generiert.Bei
follow_symlinks=Truewerden Symlinks aufgelöst und sie entsprechend ihren Zielen indirnamesundfilenamesplatziert.Das folgende Beispiel zeigt die Größe der Dateien in einem Verzeichnis an, wobei
__pycache__-Verzeichnisse ignoriert werden:>>> for root, dirs, files in p.walk(): ... print( ... root, ... "consumes", ... sum((root / file).stat().st_size for file in files), ... "bytes in", ... len(files), ... "non-directory files", ... ) ... if "__pycache__" in dirs: ... dirs.remove("__pycache__") ... docs/save-data consumes 88417 bytes in 13 non-directory files docs/save-data/sqlite consumes 35187 bytes in 19 non-directory files
Das nächste Beispiel ist eine einfache Implementierung von
shutil.rmtree(), wobei der Verzeichnisbaum von unten nach oben durchlaufen werden muss, dapathlib.Path.rmdir()das Löschen eines Verzeichnisses erst zulässt, wenn es leer ist:>>> for root, dirs, files in p.walk(top_down=False): ... for name in files: ... (root / name).unlink() ... for name in dirs: ... (root / name).rmdir() ...
Added in version 3.12.
Erstellen von Dateien und Verzeichnissen¶
pathlib.Path.touch()erstellt eine Datei unter dem angegebenen Pfad. Mit
modelassen sich Dateimodus und die Zugriffsflags angeben Wenn die Datei bereits existiert, wird die Änderungszeit auf die aktuelle Zeit aktualisiert sofernexist_ok=Trueist, andernfalls wird einFileExistsErrorausgelöst.Bemerkung
Um Dateien zu erstellen wird auch häufig
pathlib.Path.open()oderpathlib.Path.write_text()verwendet.pathlib.Path.mkdir()erstellt ein neues Verzeichnis unter dem angegebenen Pfad. Die Parameter
modeundexist_okfunktionieren wie inpathlib.Path.touch()angegeben.Wenn
parents=True, werden fehlende übergeordnete Verzeichnisse des Pfads nach Bedarf mit den Standardberechtigungen erstellt. Mit der Standardeinstellungparents=Falsewird hingegenFileNotFoundErrorausgelöst.
Verschieben, Kopieren und Löschen¶
pathlib.Path.rename()benennt die Datei oder das Verzeichnis in das angegebene Ziel um und gibt eine neue
pathlib.Path-Instanz zurück, die auf das Ziel verweist. Unter Unix wird das Ziel, sofern es existiert und eine Datei ist, einfach ersetzt, unter Windows wird einFileExistsErrorausgelöst.>>> myfile = Path("docs", "save-data", "myfile.txt") >>> newfile = Path("docs", "newdir", "newfile.txt") >>> myfile.rename(newfile) PosixPath('docs/newdir/newfile.txt')
Added in version 3.14: In Python 3.14 kommen die Methoden pathlib.Path.copy(),
pathlib.Path.copy_into(), pathlib.Path.move() und
pathlib.Path.move_into() hinzu.
Siehe auch
Berechtigungen und Eigentum¶
pathlib.Path.owner()gibt den Namen der Person zurück, der die Datei gehört. Normalerweise wird Symlinks gefolgt, wenn ihr jedoch die Person ermitteln wollt, der der Symlink gehört, fügt
follow_symlinks=Falsehinzu. Wenn die User-ID (UID) der Datei nicht gefunden wird, wirdKeyErrorausgelöst.pathlib.Path.group()gibt den Namen der Gruppe zurück, der die Datei gehört. Das Verhalten bei Symlinks entspricht dem vom
pathlib.Path.owner(). Und wenn die Group-ID (GID) der Datei nicht gefunden wird, wird ebenfallsKeyErrorausgelöst.pathlib.Path.chmod()ändert den Dateimodus und die Berechtigungen.Dabei wird normalerweise Symlinks gefolgt. Für das Ändern der Symlink-Berechtigungen, könnt ihr
follow_symlinks=Falseoderpathlib.Path.lchmod()verwenden.
Vergleich mit os und os.path¶
pathlibimplementiert mitpathlib.PurePathundpathlib.PathObjekte, währendosundos.patheher prozedural mit low-levelstr- undBytesarbeiten.Viele Funktionen in
osundos.pathunterstützen Pfade relativ zu Verzeichnisdeskriptoren. Diese Funktionen sind inpathlibnicht verfügbar.strundbytessowie Teile von:mod:`python3:osundpython3:`os.pathsind in C geschrieben und sehr schnell.pathlibist hingegen in Python geschrieben und oft langsamer, aber nicht immer spielt dies eine Rolle.
Trotz der Unterschiede lassen sich viele os-Funktionen in
entsprechende pathlib.Path- oder
pathlib.PurePath-Funktionen übersetzen:
Checks¶
Verwendet die Funktionen des
pathlib-Moduls, um einen Pfad zu einer Datei namensinstance.logzu nehmen und einen neuen Dateipfad im selben Verzeichnis für eine Datei namensinstance.log1zu erstellen.Öffnet eine Datei
my_file.txtund fügt zusätzlichen Text am Ende der Datei ein. Welchen Befehl würdet ihr verwenden, ummy_file.txtzu öffnen? Welchen Befehl würdet ihr verwenden, um die Datei erneut zu öffnen und von Anfang an zu lesen?Wenn ihr euch die Manpage für das wc-Dienstprogramm anseht, seht ihr zwei Befehlszeilenoptionen:
-czählt die Bytes in der Datei
-mzählt die Zeichen, die im Falle einiger Unicode-Zeichen zwei oder mehr Bytes lang sein können
Außerdem sollte unser Modul, wenn eine Datei angegeben wird, aus dieser Datei lesen und sie verarbeiten, aber wenn keine Datei angegeben wird, sollte es aus
stdinlesen und verarbeiten.Wenn ein Kontext-Manager in einem Skript verwendet wird, das mehrere Dateien liest und/oder schreibt, welche der folgenden Ansätze wäre eurer Meinung nach am besten?
Legt das gesamte Skript in einen Block, der von einer
with-Anweisung verwaltet wird.Verwendet eine
with-Anweisung für alle Lesevorgänge und eine weitere für alle Schreibvorgänge.Verwendet jedes Mal eine
with-Anweisung, wenn ihr eine Datei lest oder schreibt, d.h. für jede Zeile.Verwendet für jede Datei, die ihr lest oder schreibt, eine
with-Anweisung.
Archiviert
*.txt-Dateien aus dem aktuellen Verzeichnis im Verzeichnisarchiveals*.zip-Dateien mit dem aktuellen Datum als Dateiname.Welche Module benötigt ihr hierfür?
Schreibt eine mögliche Lösung.