CodeGym /Kurse /C# SELF /Datei- und Verzeichniskopie

Datei- und Verzeichniskopie

C# SELF
Level 40 , Lektion 2
Verfügbar

1. Dateikopie

Bis jetzt waren unsere Operationen im Dateisystem eher „einzelne Schläge“: Datei erstellt, gelesen, gelöscht — und fertig. In der echten Welt kommt aber oft die Aufgabe, Inhalte zu kopieren: Backup von Dokumenten, Duplizieren von Templates, Automatisierung von Datenverarbeitung. Kopieren wirkt wie eine Kinderaufgabe (Strg+C und Strg+V — unser Bestes), aber tatsächlich gibt es viele Feinheiten.

Heute schauen wir uns alle Wege an, Dateien und Ordner zu kopieren — von den simpelsten bis zu etwas komplexeren. Wir sehen auch, wie die eingebauten .NET-Klassen das lösen, welche Beschränkungen es gibt, welche Fehler auftreten können und was zu tun ist, wenn plötzlich zweitausend Verzeichnisse und eine Million Dateien vorhanden sind.

Klasse File und Methode Copy

Der einfachste Weg, eine Datei zu kopieren, ist die statische Methode File.Copy. Diese Methode nimmt den Pfad zur Quelldatei, den Pfad zur Zieldatei und einen optionalen Parameter: ob Überschreiben erlaubt ist, falls die Datei bereits existiert.

using System.IO;

// Einfaches Beispiel zum Kopieren einer Datei
File.Copy("source.txt", "destination.txt");

Wenn die Zieldatei bereits existiert, wirft die Methode eine Exception. Um explizit Überschreiben zu erlauben, nutze den dritten Parameter:

File.Copy("source.txt", "destination.txt", overwrite: true);

Wichtiger Punkt: Wenn der zweite Parameter ("destination.txt") ein Pfad zu einem vorhandenen Verzeichnis und nicht zu einer Datei ist, tritt ein Fehler auf. Die Methode erwartet einen Pfad zu einer Datei!

Arbeiten mit Pfaden

Wie immer: Vergiss nicht Path.Combine zu verwenden, damit du nicht in die Fallen mit doppelten oder falschen Slashes tappst:

string sourcePath = Path.Combine("Data", "input.txt");
string destPath = Path.Combine("Backup", "input_backup.txt");

File.Copy(sourcePath, destPath, overwrite: true);

Fehlerbehandlung

Was kann beim Kopieren einer Datei schiefgehen? Vieles: die Datei kann von einem anderen Prozess belegt sein, die Quelldatei kann fehlen, du kannst nicht die nötigen Rechte haben, das Zielmedium kann voll sein. Verwende Exception-Handling:

try
{
    File.Copy("bigdata.txt", "bigdata_backup.txt", overwrite: false);
    Console.WriteLine("Datei erfolgreich kopiert!");
}
catch (IOException ex)
{
    Console.WriteLine($"I/O-Fehler: {ex.Message}");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Kein Zugriff auf Datei oder Ordner.");
}
catch (Exception ex)
{
    Console.WriteLine($"Anderer Fehler: {ex.Message}");
}

Klasse FileInfo und Methode CopyTo

Wenn du bereits ein FileInfo-Objekt hast, kannst du darauf die Methode CopyTo aufrufen:

var fi = new FileInfo("report.xlsx");
fi.CopyTo("backup_report.xlsx");

Der dritte Parameter (overwrite) in CopyTo erschien erst in .NET Core 2.0+, also wenn du auf einer älteren Framework-Version schreibst — wundere dich nicht über einen Fehler.

Eine Datei „ins Nichts“ kopieren (oder „nicht erwischt — kein Dieb“)

Achte genau auf den angegebenen Zielpfad beim Kopieren. Wenn das Zielverzeichnis nicht existiert, wirft .NET einen Fehler. Deshalb ist es sinnvoll, vor dem Kopieren sicherzustellen, dass das Zielverzeichnis existiert:

string backupDir = "Backup";
if (!Directory.Exists(backupDir))
{
    Directory.CreateDirectory(backupDir);
}

string targetPath = Path.Combine(backupDir, "mydoc.txt");
File.Copy("mydoc.txt", targetPath);

2. Verzeichniskopie: nichts für schwache Nerven

Hier fangen die echten Abenteuer an! In .NET gibt es keine eingebaute „magische“ Methode Directory.Copy, die alles mit einer Zeile erledigt (wie bei der Klasse File). Du musst ein bisschen Handarbeit leisten und eine Funktion schreiben, die rekursiv alle Dateien und Unterordner kopiert.

Warum gibt es kein Directory.Copy?

Das Kopieren von Verzeichnissen ist nicht immer trivial. Man muss beachten, dass jeder Ordner Dateien, Unterordner, versteckte Dateien, Dateien mit speziellen Rechten und lange Pfade enthalten kann. Deshalb haben die .NET-Entwickler entschieden: „Die Entwickler sollen selbst entscheiden, was sie kopieren wollen.“ Aber wir suchen keine einfachen Wege — wir schreiben unsere eigene Funktion!

Beispiel für rekursives Kopieren eines Verzeichnisses

Aufgabe: den Inhalt eines Ordners (und seine ganze Unterwelt) in einen anderen Ordner kopieren.

using System;
using System.IO;

void CopyDirectory(string sourceDir, string destDir, bool recursive)
{
    // Prüfen, ob das Quellverzeichnis existiert
    if (!Directory.Exists(sourceDir))
        throw new DirectoryNotFoundException($"Quellordner nicht gefunden: {sourceDir}");

    // Zielordner erstellen, falls noch nicht vorhanden
    if (!Directory.Exists(destDir))
        Directory.CreateDirectory(destDir);

    // Alle Dateien kopieren
    foreach (string filePath in Directory.GetFiles(sourceDir))
    {
        string fileName = Path.GetFileName(filePath);
        string destFilePath = Path.Combine(destDir, fileName);
        File.Copy(filePath, destFilePath, overwrite: true);
    }

    // Wenn rekursiv — alle Unterordner kopieren
    if (recursive)
    {
        foreach (string dirPath in Directory.GetDirectories(sourceDir))
        {
            string dirName = Path.GetFileName(dirPath);
            string destSubDir = Path.Combine(destDir, dirName);
            // Rekursiver Aufruf!
            CopyDirectory(dirPath, destSubDir, recursive);
        }
    }
}

Verwendung:

CopyDirectory("C:\\MyData", "D:\\Backup\\MyData", recursive: true);

Diese Funktion erstellt die Verzeichnisstruktur und kopiert alle Dateien, inklusive der Inhalte der Unterordner.

Code-Analyse und Feinheiten

Zuerst erstellen wir das Zielverzeichnis (falls nicht vorhanden) — sonst würde ein Versuch, eine Datei dorthin zu kopieren, fehlschlagen. Innerhalb jeder Schleife verwenden wir Path.GetFileName, damit beim Zusammenbauen des neuen Pfads der Dateiname bzw. Ordnername nicht verloren geht.

Übrigens: Wenn du ein Verzeichnis in sich selbst oder in seinen Unterordner kopierst, bekommst du epische Rekursion … und eine StackOverflowException. Kopiere nicht "C:\\Data" nach "C:\\Data\\Backup". Der Computer wird beleidigt sein!

Nur Dateien kopieren (ohne Unterordner)

Manchmal reicht es, nur die Dateien der obersten Ebene zu kopieren (ohne in Unterordner einzutauchen):

void CopyFilesOnly(string sourceDir, string destDir)
{
    if (!Directory.Exists(destDir))
        Directory.CreateDirectory(destDir);

    foreach (string filePath in Directory.GetFiles(sourceDir))
    {
        string fileName = Path.GetFileName(filePath);
        string destFilePath = Path.Combine(destDir, fileName);
        File.Copy(filePath, destFilePath, overwrite: true);
    }
}

Beispiel — wir implementieren ein Backup

Fügen wir diese Funktionalität in unsere „HomeApp“ ein, die wir im Kurs weiterentwickeln. Sie soll jetzt eine Sicherung ihrer Daten anlegen können.

using System;
using System.IO;

namespace HomeApp
{
    class Program
    {
        static void CopyDirectory(string sourceDir, string destDir, bool recursive)
        {
            if (!Directory.Exists(sourceDir))
                throw new DirectoryNotFoundException($"Quellordner nicht gefunden: {sourceDir}");

            if (!Directory.Exists(destDir))
                Directory.CreateDirectory(destDir);

            foreach (string filePath in Directory.GetFiles(sourceDir))
            {
                string fileName = Path.GetFileName(filePath);
                string destFilePath = Path.Combine(destDir, fileName);
                File.Copy(filePath, destFilePath, overwrite: true);
            }

            if (recursive)
            {
                foreach (string dirPath in Directory.GetDirectories(sourceDir))
                {
                    string dirName = Path.GetFileName(dirPath);
                    string destSubDir = Path.Combine(destDir, dirName);
                    CopyDirectory(dirPath, destSubDir, recursive);
                }
            }
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Gib den Pfad zum Arbeitsverzeichnis ein:");
            string source = Console.ReadLine()!;
            Console.WriteLine("Gib den Pfad für das Backup-Verzeichnis ein:");
            string dest = Console.ReadLine()!;

            try
            {
                CopyDirectory(source, dest, recursive: true);
                Console.WriteLine("Backup erfolgreich erstellt!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Fehler beim Kopieren: " + ex.Message);
            }
        }
    }
}

3. Nützliche Feinheiten

Vergleich: Datei vs Verzeichnis — Tabelle

Datei Verzeichnis
Eingebaute Methode
File.Copy
-
Objektorientiert
FileInfo.CopyTo
-
Rekursion nötig Nicht erforderlich Erforderlich
Struktur erstellen Automatisch Muss manuell erstellt werden
Gefahr von Rekursion Nein Ja — nicht in sich selbst kopieren

Praktische Anwendung und Aufgaben für Selbststudium

Kopieraufgaben für Dateien und Ordner kommen überall vor: vom Backup bis zur Datenmigration oder dem Aktualisieren von Ressourcen in Game-Launchern. Meistens automatisiert man solche Prozesse, damit man nicht manuell arbeiten muss und am Montagmorgen „oh nein, eine Datei vergessen!“ ruft.

Das Kopieren von Verzeichnissen ist in allen Szenarien gefragt, in denen man nicht nur Inhalte, sondern auch das „Gerüst“ der Struktur behalten möchte, inklusive Unterordnern, eingebetteten Dateien und Einstellungen.

Checkliste fürs Kopieren (damit nichts schiefgeht)

  • Existenz der Quelle
  • Existenz des Zielordners (bei Bedarf mit Directory.CreateDirectory erstellen)
  • Strategie zum Überschreiben von Dateien — brauchst du overwrite: true?
  • Kopierst du nicht das Verzeichnis „in sich selbst“?
  • Überschreitest du nicht die Pfadlänge (besonders auf Windows)?
  • Bedenkst du versteckte/systemdateien?

4. Besonderheiten und typische Fehler beim Kopieren

Zugriffsrechte

Kopieren kann fehlschlagen, wenn dein Programm keine Leserechte für die Quelldateien oder Schreibrechte für das Zielverzeichnis hat. In diesem Fall erhältst du eine Form von UnauthorizedAccessException. Lösung: Programm als Administrator ausführen (nur wenn wirklich nötig!) oder normale Ordner zum Kopieren wählen.

Datei ist belegt

Wenn eine Datei in einem anderen Programm geöffnet ist (z.B. Excel hält sie gesperrt), kann File.Copy eine Exception werfen. Stelle sicher, dass die Anwendung, die die Datei blockiert, den Prozess nicht stört, oder implementiere Retry-Logik (try-catch mit Retries).

Überschreiben von Dateien

Welche Logik wählst du: Ziel-Dateien überschreiben oder sie unangetastet lassen, wenn sie existieren? Für Backups ist Überschreiben normalerweise sinnvoll (overwrite: true), für das Duplizieren von Templates eher nicht (overwrite: false).

Versteckte und Systemdateien kopieren

Standardmäßig geben die von uns genutzten Methoden (Directory.GetFiles) alle Dateien zurück, inklusive versteckter und systemweiter Dateien. Wenn du sie überspringen willst, filtere explizit:

foreach (string filePath in Directory.GetFiles(sourceDir))
{
    var attr = File.GetAttributes(filePath);
    if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden)
        continue; // Versteckte Dateien überspringen

    // Restlicher Kopiercode
}

Probleme mit langen Pfaden

Windows hatte lange Zeit eine Begrenzung der Pfadlänge von etwa 260 Zeichen. In modernen Versionen lässt sich diese Begrenzung aufheben, aber wenn du mit alten Systemen arbeitest, können lange Pfade problematisch sein.

Symbolische Links und Junctions

In speziellen Szenarien können in Verzeichnissen symbolische Links oder „junctions“ vorkommen. Normale Kopiermethoden können diese wie normale Ordner kopieren oder ignorieren. Für die meisten Lernaufgaben ist das unwichtig, aber bei Arbeit mit Systemverzeichnissen: Vorsicht.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION