CodeGym /Kurse /C# SELF /Massenoperationen mit Dateien

Massenoperationen mit Dateien

C# SELF
Level 40, Lektion 4
Verfügbar

1. Einführung

Stell dir ein Fotoarchiv über mehrere Jahre vor — tausende Dateien in einem Ordner (klassisch bei Windows-Benutzern), und jetzt stell dir die Aufgabe vor: nur .jpg-Dateien, die in diesem Jahr erstellt wurden, in einen separaten Ordner zum Verarbeiten zu kopieren. Oder du musst alle Berichte mit dem Präfix "old_" umbenennen, um alte und neue Versionen zu unterscheiden. Selbst wenn du nichts mit Foto-Archiven zu tun hast, werden Massenoperationen in fast jedem Projekt mit Datenverarbeitung, Logs, Backups oder Automatisierung gebraucht. Sie kommen auch in Vorstellungsgesprächen vor!

Massenoperationen sind eine super Gelegenheit, Folgendes zu lernen:

  • Schleifen und LINQ zum Durchlaufen von Verzeichnisinhalten
  • Praxis im Umgang mit Pfaden (Path)
  • Grundlagen der Filterung, Suche, Musterumbenennung
  • Wichtige Fragen: Sicherheit, Fehler, Überschreiben

Los geht's — und möge die Macht mit dir sein, das Datei-Chaos zu bändigen!

2. Massenkopieren von Dateien

Wie es funktioniert: das Grundprinzip

Für eine Massenoperation muss man normalerweise:

  1. Die Liste der benötigten Dateien bekommen (z.B. alle .txt im Ordner)
  2. Für jede Datei die gewünschte Aktion ausführen (kopieren, löschen usw.)

Das kann man so umsetzen:

  • Directory.GetFiles() — erhält die Dateiliste,
  • Schleife foreach — iteriert über jede Datei und führt die Operation aus.

Beispiel: Kopiere alle .txt-Dateien von einem Ordner in einen anderen


string sourceDir = @"C:\Source";
string destDir = @"C:\Target";

// Wir bekommen die Liste aller .txt-Dateien im Quellordner
string[] txtFiles = Directory.GetFiles(sourceDir, "*.txt");

foreach (string srcPath in txtFiles)
{
    // Nur den Dateinamen aus dem vollständigen Pfad holen
    string fileName = Path.GetFileName(srcPath);

    // Vollständigen Pfad für die Datei im Zielordner bilden
    string destPath = Path.Combine(destDir, fileName);

    // Datei kopieren
    File.Copy(srcPath, destPath, overwrite: true); // overwrite - wenn die Datei schon existiert, ersetzen
    Console.WriteLine($"Copied: {fileName}");
}

Console.WriteLine("Alle .txt-Dateien wurden erfolgreich kopiert!");

Achte darauf: in diesem Beispiel verwenden wir den Filter "*.txt" — das ist ein Suchmuster für Dateinamen, wie unter Windows üblich.

Visualisierung (Schema)

+----------------+     [*.txt]     +----------------+
|   C:\Source    | ---filter-----> |   C:\Target    |
| a.txt          |   foreach +     |                |
| b.txt          | --copy--------> | a.txt (copied) |
| c.jpg          |                | b.txt (copied) |
+----------------+                +----------------+
(.jpg-Dateien werden ignoriert, nur .txt werden kopiert)

3. Massenlöschung von Dateien

Massenlöschung von Dateien ist eine sehr populäre Operation. Zum Beispiel muss man häufig temporäre Dateien bereinigen, alte Logs automatisch löschen oder jpg-Fotos entfernen, die nicht mehr gebraucht werden.

Beispiel: Lösche alle Dateien, die älter als 30 Tage sind


string dir = @"C:\MyLogs";
int daysOld = 30;

DirectoryInfo di = new DirectoryInfo(dir);
// Alle Dateien im Ordner bekommen
foreach (FileInfo file in di.GetFiles())
{
    // Prüfen des letzten Änderungsdatums
    if (file.LastWriteTime < DateTime.Now.AddDays(-daysOld))
    {
        file.Delete();
        Console.WriteLine($"Gelöscht: {file.Name}");
    }
}

Tipp: FileInfo.LastWriteTime ist super praktisch für Bedingungen "älter als N Tage".

4. Massenumbenennung von Dateien

Manchmal muss man viele Dateien nach einem Muster umbenennen. Zum Beispiel einen gemeinsamen Präfix hinzufügen, Erweiterungen ändern oder einfach durchnummerieren. In .NET läuft das ähnlich ab — Liste der Dateien holen und dann mit File.Move() umbenennen.

Beispiel: Füge den Präfix "old_" zu allen .docx-Dateien hinzu


string dir = @"C:\Reports";

string[] docxFiles = Directory.GetFiles(dir, "*.docx");
foreach (string oldPath in docxFiles)
{
    string dirPath = Path.GetDirectoryName(oldPath)!;
    string fileName = Path.GetFileName(oldPath);
    string newPath = Path.Combine(dirPath, "old_" + fileName);

    // Umbenennen (eigentlich ein Verschieben in denselben Ordner mit neuem Namen)
    File.Move(oldPath, newPath);
    Console.WriteLine($"Umbenannt: {fileName} -> old_{fileName}");
}

Wichtiger Punkt: wenn im Ordner schon eine Datei mit dem neuen Namen existiert, wird eine Ausnahme ausgelöst. Man kann das mit try-catch abfangen, falls nötig.

5. Kopieren ganzer Verzeichnisse mit Inhalt

Für einfache Aktionen mit einem Ordner gibt es kein Ein-Zeilen-"Ordner kopieren" (es gibt kein Directory.Copy — das ist eine Falle für Jedis!). Man muss manuell vorgehen:

  1. Zielordner erstellen (falls nicht vorhanden)
  2. Alle Dateien kopieren (siehe bekanntes Beispiel)
  3. Alle Unterordner rekursiv kopieren (jeden als neue Kopieraufgabe behandeln)

Universelle Funktion: Ordner rekursiv kopieren


using System;
using System.IO;

class Program
{
    static void CopyDirectory(string sourceDir, string destDir, bool overwrite = true)
    {
        // Ordner erstellen, falls nicht vorhanden
        Directory.CreateDirectory(destDir);

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

        // Alle Unterordner rekursiv kopieren
        foreach (string subDir in Directory.GetDirectories(sourceDir))
        {
            string dirName = Path.GetFileName(subDir);
            string destSubDir = Path.Combine(destDir, dirName);
            CopyDirectory(subDir, destSubDir, overwrite);
        }
    }

    static void Main()
    {
        string source = @"C:\Archive2023";
        string target = @"D:\Backup2023";
        CopyDirectory(source, target);
        Console.WriteLine("Verzeichnis erfolgreich kopiert!");
    }
}

Blockdiagramm

            CopyDirectory(A, B)
               /          \
      Dateien kopieren   foreach subDir -> CopyDirectory(subDir, destSubDir)

6. Massenfilterung, Suche und Verarbeitung von Dateien

Angenommen, du willst nicht nur einen Ordner durchlaufen, sondern nach mehreren Kriterien filtern: z.B. nur Bilder, deren Größe größer als 5 MB ist und die im Jahr 2024 erstellt wurden! Dafür ist die Kombination von LINQ mit den Dateisystemklassen praktisch.

Beispiel: Gib die Namen großer und aktueller Bilder aus


string dir = @"C:\Pictures";

var filtered = new DirectoryInfo(dir)
    .GetFiles("*.jpg")
    .Where(f => f.Length > 5_000_000 && f.CreationTime.Year == 2024);

foreach (var file in filtered)
{
    Console.WriteLine($"{file.Name} ({file.Length / 1024 / 1024} MB)");
}

In diesem Beispiel nutzen wir LINQ für "Chaining" der Filter — und schreiben realistischen Code, wie er im Job vorkommt.

7. Durchlauf durch verschachtelte Ordner: Rekursion und Iteration

Oft muss man nicht nur ein Verzeichnis bearbeiten, sondern alle Unterverzeichnisse (z.B. alle temporären Dateien in der gesamten Archivstruktur löschen). Methoden zum Holen von Dateien (Directory.GetFiles und DirectoryInfo.GetFiles) haben eine Variante mit dem speziellen Parameter SearchOption.AllDirectories, der das für dich übernimmt!

Beispiel: Finde und lösche alle .tmp-Dateien in allen Unterordnern


string root = @"D:\BigFolder";
string[] tmpFiles = Directory.GetFiles(root, "*.tmp", SearchOption.AllDirectories);

foreach (string file in tmpFiles)
{
    File.Delete(file);
    Console.WriteLine($"Gelöscht: {file}");
}
Console.WriteLine("Alle temporären Dateien wurden gelöscht.");

Achtung: Sei vorsichtig mit diesem Flag — es kann Dateien selbst in sehr tiefen Verschachtelungen finden!

8. Massenerstellung von Dateien und Verzeichnissen

Manchmal ist die umgekehrte Aufgabe gefragt — automatisch die benötigte Verzeichnisstruktur erstellen oder viele Dateien generieren.

Beispiel: Erzeuge 10 Ordner und 10 Dateien in jedem


string root = @"C:\GeneratedFolders";

for (int i = 1; i <= 10; i++)
{
    string subDir = Path.Combine(root, $"Folder_{i}");
    Directory.CreateDirectory(subDir);

    for (int j = 1; j <= 10; j++)
    {
        string filePath = Path.Combine(subDir, $"File_{j}.txt");
        File.WriteAllText(filePath, $"Das ist Datei Nummer {j} im Ordner {i}");
    }
}

Console.WriteLine("Ordner und Dateien wurden erstellt!");

Tipp: Damit lässt sich schnell Testinfrastruktur aufbauen, "Dummy"-Daten für Tests, Lernen usw. generieren.

9. Massenverschieben von Dateien

Ähnlich wie beim Kopieren, nur dass du File.Move statt File.Copy verwendest. Gut geeignet zum Sortieren von Dateien in Ordner.

Beispiel: Sortiere Dateien nach Erweiterungen

Stell dir vor: im Ordner liegen viele Dateien verschiedener Typen, und du willst sie nach Ordnern .jpg, .pdf, .docx usw. sortieren.


string source = @"C:\Downloads";
string[] files = Directory.GetFiles(source);

foreach (string path in files)
{
    string ext = Path.GetExtension(path).TrimStart('.').ToUpper(); // "JPG", "PDF", "DOCX"
    if (string.IsNullOrEmpty(ext)) ext = "OTHER";
    string destDir = Path.Combine(source, ext);

    Directory.CreateDirectory(destDir); // kein Problem, wenn schon vorhanden

    string fileName = Path.GetFileName(path);
    string destPath = Path.Combine(destDir, fileName);

    if (!File.Exists(destPath))
    {
        File.Move(path, destPath);
        Console.WriteLine($"Verschoben: {fileName} -> {destDir}");
    }
    else
    {
        Console.WriteLine($"Datei existiert bereits in {destDir}, überspringe: {fileName}");
    }
}

Die Dateien verteilen sich in "Boxen" und du fühlst dich wie ein digitaler Marie Kondo.

10. Typische Fehler und Feinheiten bei Massenoperationen

Wenn du mit Hunderten arbeitest statt mit einer Datei, tauchen interessante Details auf.

Zum Beispiel können einige Dateien von einer anderen Anwendung geöffnet sein — der Versuch, sie zu löschen oder zu kopieren, führt zu einem Fehler. Auch kommt es häufig vor, dass im Zielordner schon eine Datei mit dem gewünschten Namen existiert. Wenn die Konstruktion kein Überschreiben vorsieht, stürzt der Code mit einer Ausnahme ab. Manchmal fehlen Zugriffsrechte für Dateien oder Ordner, oder du löschst versehentlich etwas Wichtiges rekursiv.

Der klassische Fehler ist, Operationen ohne Fehlerbehandlung durchzuführen: wenn mitten im Prozess ein Fehler auftritt (z.B. fehlende Rechte für eine Datei), bricht die Schleife ab und alle weiteren Aktionen werden nicht ausgeführt. Deshalb verwendet man für zuverlässige Massenoperationen fast immer Exception-Handling mit try-catch innerhalb der Schleife, damit problematische Dateien übersprungen werden können und der Rest trotzdem bearbeitet wird.

Und vergiss die Überschreib-Parameter nicht: wo es sinnvoll ist, nutze overwrite: true in File.Copy, und beim Umbenennen/Verschieben prüfe vorher, ob die Zieldatei existiert, oder verwende eine Konfliktstrategie (Umbenennen mit Suffix, Überspringen, Logging).

2
Aufgabe
C# SELF, Level 40, Lektion 4
Gesperrt
Dateien nach Erweiterung in Ordner sortieren
Dateien nach Erweiterung in Ordner sortieren
1
Umfrage/Quiz
Dateien erstellen und löschen, Level 40, Lektion 4
Nicht verfügbar
Dateien erstellen und löschen
Dateien und Verzeichnisse verwalten
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION