HOWTO · Python
Lesen der letzten Zeile einer Datei mit Python
Wir können die for-Schleife und die Funktion file.readlines() verwenden, um die letzte Zeile einer Datei in Python zu lesen.
Auf dieser Seite
Um die letzte Zeile in Python zu erhalten, durchlaufe die Datei und speichere jeweils die zuletzt gelesene Zeile. Dabei wird die Datei vom Anfang bis zum Ende gelesen, aber es wird immer nur eine Zeile gespeichert. Wenn das bei einer sehr großen Datei zu lange dauert, kannst du stattdessen in binären Blöcken rückwärts lesen.
Führe dieses Beispiel aus. Die Codebeispiele und ihre sichtbaren Beschriftungen bleiben unverändert auf Englisch:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("alpha\nbeta\ngamma\n", encoding="utf-8")
last_line = None
with path.open("r", encoding="utf-8") as file:
for line in file:
last_line = line.rstrip("\r\n")
print(last_line)
gamma
Die letzte Zeile einer Datei mit Python lesen
Python-Dateiobjekte bieten keine direkte Funktion zum Lesen der „letzten Zeile“. Das zeilenweise Lesen ist einfach und benötigt wenig zusätzlichen Speicher, muss aber trotzdem bis zum Dateiende gelangen. Ist die Datei klein genug, um bequem in den Arbeitsspeicher zu passen, ist readlines() die kürzere Variante. Bei einer großen Datei kann ein rückwärts gerichteter Binärdurchlauf vermeiden, frühere Inhalte zu lesen. Welche Methode am besten passt, hängt davon ab, ob Einfachheit, Speicherbedarf oder das Vermeiden eines vollständigen Durchlaufs am wichtigsten ist.
Zeilenweise mit einer for-Schleife lesen
Speichere die zuletzt gelesene Zeile in einer Variablen. Wenn du sie mit None initialisierst, erhält der Code auch für eine Datei ohne Zeilen ein definiertes Ergebnis. rstrip("\r\n") entfernt nur Zeichen für Zeilenenden, sodass Leerzeichen im eigentlichen Inhalt erhalten bleiben.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("first\nsecond\n", encoding="utf-8")
last_line = None
with path.open("r", encoding="utf-8") as file:
for line in file:
last_line = line.rstrip("\r\n")
print(last_line)
Die Schleife liest jede Zeile; der Zeitaufwand steigt daher mit der Dateigröße. Der zusätzliche Speicherbedarf beschränkt sich auf die aktuelle Zeile und das gespeicherte Ergebnis. Ein abschließender Zeilenumbruch erzeugt im Text-Iterator von Python keine zusätzliche Zeile. Eine leere letzte Zeile, die durch zwei Zeilenumbrüche dargestellt wird, wird als leerer String zurückgegeben.
readlines() für kleine Dateien verwenden
readlines() gibt alle Zeilen als Liste zurück, sodass sich das letzte Element leicht auswählen lässt. Prüfe die Liste vor dem Zugriff, denn bei einer leeren Datei ist sie leer. Im Textmodus bleibt das jeweilige Zeilenende im zurückgegebenen String enthalten. Wenn du den Inhalt ohne Zeilenabschluss benötigst, entferne nur \r und \n.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("first\nsecond\n", encoding="utf-8")
with path.open("r", encoding="utf-8") as file:
lines = file.readlines()
last_line = lines[-1].rstrip("\r\n") if lines else None
print(last_line)
Auch diese Methode liest die gesamte Datei ein und hält alle Zeilen im Speicher. Verwende sie, wenn du die Liste anderweitig brauchst oder die Datei überschaubar ist. Vermeide strip(), wenn führende oder abschließende Leerzeichen eine Bedeutung haben können.
Mit deque nur die letzte Zeile behalten
Eine deque mit maxlen=1 verwirft ältere Einträge, sobald eine neue Zeile hinzukommt. Sie liest die Datei wie die Schleife der Reihe nach und benötigt wenig Speicher, kommt aber mit weniger expliziter Zustandsverwaltung aus. Prüfe das Ergebnis, bevor du pop() aufrufst, damit die Funktion auch eine Datei ohne Zeilen verarbeiten kann.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from collections import deque
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_text("first\nsecond\n", encoding="utf-8")
with path.open("r", encoding="utf-8") as file:
lines = deque(file, maxlen=1)
last_line = lines.pop().rstrip("\r\n") if lines else None
print(last_line)
deque begrenzt die Zahl der gespeicherten Zeilen, nicht die Menge der eingelesenen Daten: Die Methode liest weiterhin bis zum Dateiende. Sie eignet sich, wenn du beim Einlesen einer Datei nur den jeweils neuesten Eintrag behalten möchtest.
Mit seek() vom Dateiende rückwärts lesen
Bei einer großen Datei kannst du sie im Binärmodus öffnen und mit seek() sicher zu Bytepositionen springen. Die folgende Funktion beginnt am Dateiende, entfernt gegebenenfalls einen abschließenden Zeilenvorschub und sucht anschließend in gleich großen Blöcken rückwärts nach dem vorhergehenden Zeilenvorschub. Sie setzt nur die Blöcke zusammen, die zur letzten Zeile gehören. Der Speicherbedarf richtet sich daher nach der Länge dieser Zeile und nicht nach der gesamten Datei. Die Methode unterstützt LF- und CRLF-Zeilenenden und dekodiert die ausgewählten Bytes mit der angegebenen Kodierung.
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
from pathlib import Path
from tempfile import TemporaryDirectory
def read_last_line(path, encoding="utf-8", chunk_size=8192):
if chunk_size <= 0:
raise ValueError("chunk_size must be positive")
with open(path, "rb") as file:
file.seek(0, 2)
end = file.tell()
if end == 0:
return None
file.seek(end - 1)
position = end - 1 if file.read(1) == b"\n" else end
chunks = []
while position > 0:
start = max(0, position - chunk_size)
file.seek(start)
chunk = file.read(position - start)
newline = chunk.rfind(b"\n")
if newline >= 0:
chunks.append(chunk[newline + 1:])
line = b"".join(reversed(chunks))
return (line[:-1] if line.endswith(b"\r") else line).decode(encoding)
chunks.append(chunk)
position = start
line = b"".join(reversed(chunks))
return (line[:-1] if line.endswith(b"\r") else line).decode(encoding)
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
path.write_bytes("first\r\nlast line\r\n".encode("utf-8"))
print(read_last_line(path))
Ist eine Zeile länger als ein Block, werden weitere Blöcke gesammelt, bis ihr Trennzeichen gefunden ist. Bei einer Datei mit nur einer Zeile wird bis zum Anfang zurückgelesen. Die ausgewählten Bytes müssen in der angegebenen Kodierung gültig sein. Diese Implementierung behandelt LF und CRLF als Trennzeichen, aber keine Dateien, in denen einzelne CR-Zeichen Zeilen trennen. Bei ungewöhnlichen Kodierungen oder Zeilenenden solltest du einen zeilenweisen Text-Reader verwenden oder die Behandlung der Trennzeichen anpassen.
tail auf Unix-ähnlichen Systemen verwenden
Auf Systemen, die den externen Befehl tail bereitstellen, kannst du damit die letzte Zeile ausgeben lassen, ohne selbst einen rückwärts gerichteten Durchlauf zu implementieren. Rufe den Befehl aus Python auf und erfasse seine Bytes mit subprocess.run(["tail", "-n", "1", path], capture_output=True, check=True). Dekodiere anschließend result.stdout mit der Kodierung der Datei. Dafür muss tail installiert und über PATH verfügbar sein; unter Windows ist dies keine native Lösung. Verwende eine Argumentliste, statt aus einem Pfad einen Shell-Befehl zusammenzusetzen. Verhalten und Geschwindigkeit hängen vom Betriebssystem und von der Datei ab.
Eine Methode auswählen und Randfälle berücksichtigen
| Methode | Wird die ganze Datei gelesen? | Zusätzlicher Speicher | Geeignet, wenn … |
|---|---|---|---|
for-Schleife |
Ja | Eine Zeile | du unkomplizierten Streaming-Code möchtest. |
readlines() |
Ja | Alle Zeilen | die Datei klein ist oder du die Liste benötigst. |
deque mit maxlen=1 |
Ja | Eine Zeile | du den Streaming-Zustand knapp halten möchtest. |
Binäre Blöcke rückwärts mit seek() |
Meistens nicht; bei einer langen letzten Zeile kann bis zum Anfang gelesen werden | Letzte Zeile plus ein Block | die Datei groß ist und LF oder CRLF verwendet wird. |
tail |
Abhängig von der Implementierung | Externer Prozess | das Zielsystem den Befehl bereitstellt. |
Gib bei einer leeren Datei None oder einen anderen dokumentierten Ersatzwert zurück, statt ungeprüft auf ein Element zuzugreifen oder pop() aufzurufen. Entscheide, ob das Ergebnis den Zeilenabschluss enthalten soll. Wenn nicht, entferne nur \r und \n. Die Schleife und deque benötigen wenig Speicher, durchlaufen aber trotzdem die gesamte Datei. readlines() ist die einfachste listenbasierte Möglichkeit für kleine Dateien. Verwende den rückwärts gerichteten seek()-Ansatz, wenn das Vermeiden früherer Lesezugriffe wichtig ist und die Annahmen zu Kodierung und Zeilenenden zur Datei passen. Wähle tail, wenn ein externes Unix-ähnliches Werkzeug infrage kommt.