Python-Kurs / Dateien mit Probelauf kopieren und Überschreiben verhindern

Beginnen Sie eine Datei-Automatisierung mit einem Probelauf, der die beabsichtigten Kopien anzeigt. Das folgende vollständige Python-Beispiel kopiert erst mit --apply, erhält die Quelldateien und verweigert das Überschreiben vorhandener Ziele.

Arbeitsordner und Erhaltungsregeln festlegen

Verwenden Sie einen neuen, leeren Übungsordner und prüfen Sie im Terminal den aktuellen Ordner. Beide Programme verwenden relative Pfade unter copy-demo/in und copy-demo/out; sie beziehen sich auf das Arbeitsverzeichnis des Prozesses und nicht automatisch auf den Speicherort der Python-Datei. Starten Sie die Programme deshalb aus dem vorgesehenen Übungsordner. Verwenden Sie dafür keine vorhandenen Geschäfts- oder Dokumentenordner.

Der Kopierlauf berücksichtigt nur unmittelbar im Eingangsordner gefundene *.txt-Dateien. Er durchsucht Unterordner nicht rekursiv und schließt als symbolische Links erkannte Eingabedateien aus. Die Quelle wird weder verschoben noch gelöscht. Bei Namenskollisionen endet der Lauf mit einem Fehler, statt den bisherigen Inhalt zu ersetzen oder unbemerkt einen anderen Dateinamen zu wählen.

Trennen Sie die Vorbereitung vom Probelauf: Die Vorbereitung erzeugt bewusst eine Beispieldatei. Speichern Sie das folgende vollständige Programm als setup_copy.py mit UTF-8 und führen Sie in Ihrer Projektumgebung einmal python setup_copy.py aus. Die Standardbibliothek genügt; unter macOS oder Ubuntu kann außerhalb einer virtuellen Umgebung der Interpreterbefehl python3 heißen.

from pathlib import Path
source = Path("copy-demo/in")
source.mkdir(parents=True, exist_ok=True)
with (source / "note.txt").open("x", encoding="utf-8") as f:
    f.write("demo\n")
print("sample ready")

Die Meldung sample ready bestätigt die Vorbereitung. Der Modus x erstellt note.txt exklusiv: Bei einer Wiederholung mit vorhandener Datei erhalten Sie FileExistsError, ohne deren Inhalt zu überschreiben. Wenn Sie diese Meldung sehen, prüfen Sie die bereits erzeugte Datei, bevor Sie mit der Kopierübung fortfahren.

Den Probelauf ohne Zieldatei ausführen

Speichern Sie als zweite vollständige Datei safe_copy.py im selben Übungsordner:

import argparse
import hashlib
import shutil
from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
source, target = Path("copy-demo/in"), Path("copy-demo/out")
if not source.is_dir():
    parser.error("prepare copy-demo/in first")
files = sorted(p for p in source.glob("*.txt") if p.is_file() and not p.is_symlink())
for src in files:
    dst = target / src.name
    if dst.exists() or dst.is_symlink():
        raise FileExistsError(dst)
    print("copy", src.name)
    if args.apply:
        target.mkdir(parents=True, exist_ok=True)
        with src.open("rb") as incoming, dst.open("xb") as outgoing:
            shutil.copyfileobj(incoming, outgoing)
        if hashlib.sha256(src.read_bytes()).digest() != hashlib.sha256(dst.read_bytes()).digest():
            raise RuntimeError("copy verification failed")
print("applied" if args.apply else "dry-run")

Starten Sie zunächst nur python safe_copy.py, ohne Zusatzoption. Nach der Vorbereitung ergibt sich folgende Ausgabe:

copy note.txt
dry-run

In diesem ersten Durchlauf wird kein Ausgangsordner und keine Kopie erzeugt. copy note.txt ist die angekündigte Aktion, keine Bestätigung einer bereits geschriebenen Datei. argparse wertet die ausdrücklich angegebene Option aus; args.apply ist ohne sie falsch. Wenn der Eingangsordner fehlt, beendet parser.error das Programm mit einer Fehlermeldung.

Die Liste wird vor der Schleife sortiert, die Zielkollision aber erst je Datei geprüft. Ein Probelauf kann deshalb bereits beim Lesen der vorhandenen Ziele scheitern. Prüfen Sie neben der sichtbaren Liste auch, ob Sie im richtigen Arbeitsverzeichnis sind. Grundlagen dazu vermittelt der Kurs zu pathlib und Dateipfaden.

Die geprüfte Kopie anwenden und ihren Inhalt kontrollieren

Wenn der Probelauf das erwartete Ziel zeigt, starten Sie:

python safe_copy.py --apply

Beim ersten erfolgreichen Kopieren erscheinen copy note.txt und applied. Jetzt existiert copy-demo/out/note.txt. Die Quelle muss weiterhin vorhanden sein, und beide Dateien müssen denselben Inhalt besitzen. rb liest Bytes; xb erstellt das Ziel ausschließlich als neue Binärdatei. So werden die Bytes kopiert, ohne dabei die Textkodierung oder Zeilenenden umzuwandeln.

shutil.copyfileobj überträgt den Inhalt zwischen den geöffneten Dateien. Die with-Blöcke schließen beide Dateien, bevor der Code sie zur Prüfung erneut liest. Anschließend werden SHA-256-Prüfsummen verglichen. Diese Prüfung erkennt hier abweichende Dateiinhalte; sie ist keine Prüfung aller Dateieigenschaften und keine Sicherung gegen jede gleichzeitige Änderung.

Starten Sie dieselbe Anwendung erneut, muss sie mit FileExistsError abbrechen und das vorherige Ziel erhalten. Selbst der Probelauf meldet nach einer bereits erfolgten Kopie die vorhandene Zielkollision. Die Beispiele sind bewusst keine automatische Synchronisation, die vorhandene Dateien aktualisiert. Einzelheiten zu Inhaltskopien finden Sie in der Referenz zu shutil.copyfileobj; die Referenz zu open erläutert die Öffnungsmodi.

Teilweise Ergebnisse und Grenzen berücksichtigen

Die Schleife ist keine Transaktion. Wenn bei einer späteren Datei eine Kollision oder ein Schreibfehler auftritt, können frühere Kopien bereits vollständig vorhanden sein. Ein Schreibabbruch kann außerdem eine unvollständige neue Zieldatei zurücklassen. Ein erneuter Lauf darf diese nicht stillschweigend überschreiben. Notieren Sie die betroffenen Pfade, vergleichen Sie Quelle und Ziel und entscheiden Sie erst danach über die Wiederaufnahme.

Die Übertragung selbst liest standardmäßig abschnittsweise. Die beiden anschließenden read_bytes()-Aufrufe für die Hashprüfung laden jedoch jeweils den vollständigen Dateiinhalt. Für große Dateien sollten Sie auch die Prüfsumme blockweise berechnen. Kopiert wird in diesem Beispiel der Dateninhalt, nicht zuverlässig alles an Zugriffsrechten, Besitzinformationen, Zeitstempeln oder weiteren plattformspezifischen Metadaten.

Die ausgeschlossenen Eingabelinks machen das Programm außerdem nicht zu einer geschützten Dateiumgebung. Insbesondere prüft es nicht jeden Elternpfad darauf, ob ein anderer Benutzer ihn gleichzeitig austauscht oder umleitet. Verwenden Sie die Übung deshalb in einem von Ihnen kontrollierten Ordner. Die Pathlib-Referenz zu symbolischen Links beschreibt die einzelnen Pfadabfragen.

  1. Vergleichen Sie direkt nach der Vorbereitung den Probelauf mit dem ersten Anwenden: Erst Letzteres darf den Ausgangsordner erzeugen.
  2. Prüfen Sie nach der Kopie beide Dateien und wiederholen Sie den Anwenden-Befehl. Die Fehlermeldung muss auftreten, ohne Quelle oder vorheriges Ziel zu verändern.
  3. Wenn Sie weitere Testdateien hinzufügen, berücksichtigen Sie die sortierte Reihenfolge und die Möglichkeit bereits fertiger Kopien vor einem späteren Fehler. Sichern und prüfen Sie die Ergebnisse, bevor Sie einen erneuten Lauf planen.

Bevor Sie später Umbenennen, Verschieben oder Löschen ergänzen, benötigen diese Schritte eine eigene Zielliste, Kollisionsregel und Wiederherstellungsstrategie. Wenn Sie Übungsdateien aufräumen, prüfen Sie vorher die aufgelösten absoluten Pfade und beschränken Sie die Auswahl auf die bewusst erzeugten Ergebnisse im vorgesehenen copy-demo-Ordner.