## 12.2 Laufwerke, Verzeichnisse und Dateien Die Klassenbibliothek des .NET Frameworks unterstützt den Entwickler mit mehreren Klassen, die Laufwerke, Verzeichnisse und Dateien beschreiben. Diese wollen wir als Erstes ansehen. Dabei handelt es sich um: File FileInfo Directory DirectoryInfo Path DriveInfo SpecialDirectories File bzw. FileInfo und Directory bzw. DirectoryInfo liefern sehr ähnliche Daten zurück. Bei File/FileInfo handelt es um Daten, die eine Datei betreffen, bei Directory/DirectoryInfo um Daten von Verzeichnissen. Möchten Sie Pfadangaben ermitteln, hilft Ihnen Path weiter. Erwähnenswert sind zudem DriveInfo, um Laufwerksinformationen abzufragen, und SpecialDirectories, um die Pfade Windows-eigener Verzeichnisse zu erhalten. ### 12.2.1 Die Klasse »File« #### Methoden der Klasse »File« Die nicht ableitbare Klasse File stellt nur statische Methoden zur Verfügung. Die Methoden von FileInfo sind Instanzmethoden und werden über eine Objektreferenz aufgerufen. Funktionell sind sich beide Klassen jedoch ähnlich und unterscheiden sich nicht gravierend. Mit den Klassenmethoden von File lässt sich eine Datei erstellen, kopieren, löschen usw. Sie können auch die Attribute einer Datei lesen oder setzen, und – was auch sehr wichtig ist – Sie können eine Datei öffnen. In Tabelle 12.1 sind die wichtigsten Methoden samt Rückgabetyp aufgeführt.

Tabelle 12.1 Methoden der Klasse »File«

Methode | Rückgabetyp | Beschreibung
AppendAllText | void | Öffnet eine Datei und fügt die angegebene Zeichenfolge an die Datei an.
AppendText | StreamWriter | Hängt Text an eine existierende Datei an.
Copy | void | Kopiert eine bestehende Datei an einen anderen Speicherort.
Create | FileStream | Erzeugt eine Datei in einem angegebenen Pfad.
CreateText | StreamWriter | Erstellt oder öffnet eine Textdatei.
Delete | void | Löscht eine Datei.
Exists | Boolean | Gibt einen booleschen Wert zurück, der false ist, wenn die angegebene Datei nicht existiert.
GetAttributes | FileAttributes | Liefert das Bitfeld der Dateiattribute.
GetCreationTime | DateTime | Liefert das Erstellungsdatum und die Uhrzeit einer Datei.
GetLastAccessTime | DateTime | Liefert Datum und Uhrzeit des letzten Zugriffs.
GetLastWriteTime | DateTime | Liefert Datum und Uhrzeit des letzten Schreibzugriffs.
Move | void | Verschiebt eine Datei in einen anderen Ordner oder benennt sie um.
Open | FileStream | Öffnet eine Datei.
OpenRead | FileStream | Öffnet eine Datei zum Lesen.
OpenText | StreamReader | Öffnet eine Textdatei zum Lesen.
OpenWrite | FileStream | Öffnet eine Datei zum Schreiben.
ReadAllBytes | byte[] | Öffnet eine Binärdatei und liest den Inhalt der Datei in ein Byte-Array ein.
ReadAllLines | string[] | Öffnet eine Textdatei und liest alle Zeilen der Datei in ein Zeichenfolgen-Array ein.
ReadAllText | string | Öffnet eine Textdatei, liest alle Zeilen der Datei in eine Zeichenfolge ein und schließt dann die Datei.
SetAttributes | void | Setzt Dateiattribute.
SetCreationTime | void | Setzt Erstellungsdatum und -uhrzeit.
SetLastAccessTime | void | Setzt Datum und Uhrzeit des letzten Zugriffs.
SetLastWriteTime | void | Setzt Datum und Uhrzeit des letzten Schreibzugriffs.
WriteAllBytes | void | Erstellt eine neue Datei und schreibt das angegebene Byte-Array in die Datei.
WriteAllLines | void | Erstellt eine neue Datei und schreibt das angegebene Zeichenfolgen-Array in die Datei.
WriteAllText | void | Erstellt eine neue Datei und schreibt das angegebene Zeichenfolgen-Array in die Datei.
Wie Sie sehen können, geben viele Methoden ein Stream-Objekt zurück. Das hat seinen Grund, denn mit einer geöffneten Datei will man arbeiten, sei es, um den Inhalt zu lesen, oder sei es, um etwas in die Datei zu schreiben. Diese Operationen setzen aber einen Stream voraus, was das .NET Framework durch die Definition verschiedener Stream-Klassen abdeckt. Ein FileStream beschreibt dabei einfache Byte-Sequenzen, ein StreamReader basiert auf einer Textdatei. #### Datei kopieren Zum Kopieren einer Datei dient die Methode Copy, beispielsweise so:
    File.Copy("C:\\Test.txt", "D:\\Test.txt");
Das erste Argument erwartet die Angabe des Dateinamens der Datei, die Sie kopieren wollen. Befindet sich die zu kopierende Datei in keinem bekannten Suchpfad, muss der gesamte Zugriffspfad beschrieben werden. Im zweiten Argument müssen Sie das Zielverzeichnis und den Namen der Dateikopie angeben. Den Namen der kopierten Datei dürfen Sie gemäß den systemspezifischen Richtlinien festlegen, er muss nicht mit dem Ursprungsnamen der Datei übereinstimmen. Versucht man, ein Ziel anzugeben, in dem bereits eine gleichnamige Datei existiert, wird die Ausnahme DirectoryNotFoundException ausgelöst. Wenn Sie die Pfadangabe in einem string-Literal festlegen, müssen Sie beachten, dass das einfache Backslash-Zeichen in einem Literal als Escape-Zeichen interpretiert wird. Sie müssen deshalb zwei Backslashes hintereinander angeben oder alternativ der Zeichenfolge ein @-Zeichen voranstellen.
    File.Copy(@"C:\Test.txt", @"D:\Test.txt");
Sie können die Methode Copy auch einsetzen, wenn im Zielverzeichnis bereits eine Datei existiert, die denselben Namen hat wie die Datei, die Sie im zweiten Argument angeben. Dann müssen Sie die Überladung von Copy benutzen, die im dritten Parameter einen booleschen Wert erwartet. Übergeben Sie true, wird keine Ausnahme ausgelöst, und die bereits vorhandene Datei wird durch den Inhalt der im ersten Argument übergebenen Datei überschrieben. #### Datei löschen Zum Löschen einer Datei ruft man die statische Methode Delete auf und übergibt dieser als Argument den kompletten Pfad der zu löschenden Datei, z. B. so:
    File.Delete(@"C:\MyDocuments\MyDoc.txt");
Die Pfadangabe kann absolut oder relativ sein. #### Datei verschieben Mit Move lassen sich Dateien aus einem Quellverzeichnis in ein anderes Zielverzeichnis verschieben:
    File.Move(@"C:\MyDocuments\MyDoc.txt", @"C:\Allgemein\MyDoc.Doc");
Diese Methode kann auch zum Umbenennen von Dateinamen benutzt werden. #### Prüfen, ob eine Datei existiert Beabsichtigen Sie, eine bestimmte Datei zu öffnen, stellt sich zunächst die Frage, ob eine Datei dieses Namens in dem angegebenen Pfad tatsächlich existiert. Die Klasse File veröffentlicht zur Beantwortung die Methode Exists, die den booleschen Wert false zurückliefert, wenn die Datei nicht gefunden wird.
    string path = @"C:\MyFile.txt";
    if (File.Exists(path)) {
      // Datei existiert im angegebenen Pfad
    }
Eine ähnliche Codesequenz dürfte in jedem Programm sinnvoll sein, in dem eine Operation die Existenz einer Datei zwingend voraussetzt. Das erspart die Codierung einer Ausnahmebehandlung. #### Datei öffnen Zum Öffnen einer Datei benutzen Sie eine der Methoden OpenRead, OpenText, OpenWrite oder Open (siehe auch Tabelle 12.1). Sehen wir uns exemplarisch die komplexeste Überladung der letztgenannten Methode an.
    public static FileStream Open(string path, FileMode mode,
                                  FileAccess access, FileShare share);
Dem Parameter path wird beim Aufruf die Pfadangabe als Zeichenfolge mitgeteilt. Diese besteht aus dem Pfad und dem Dateinamen. Für das Öffnen einer Datei ist das Betriebssystem zuständig, das wissen muss, wie es die Datei öffnen soll. Der mode-Parameter vom Typ FileMode steuert dieses Verhalten. Dabei handelt es sich um eine im Namespace System.IO definierte Enumeration, die insgesamt sechs Konstanten definiert (siehe Tabelle 12.2).

Tabelle 12.2 Die Konstanten der Enumeration »FileMode«

FileMode-Konstante | Beschreibung
Append | Öffnet eine bestehende Datei und setzt den Dateizeiger an das Dateiende. Damit wird das Anhängen von Dateninformationen an die Datei ermöglicht. Existiert die Datei noch nicht, wird sie erzeugt.
Create | Erzeugt eine neue Datei. Existiert bereits eine gleichnamige Datei, wird diese überschrieben.
CreateNew | Erzeugt in jedem Fall eine neue Datei. Existiert im angegebenen Pfad bereits eine gleichnamige Datei, wird die Ausnahme IOException ausgelöst.
Open | Öffnet eine bestehende Datei. Wird diese unter der Pfadangabe nicht gefunden, kommt es zur Ausnahme FileNotFoundException.
OpenOrCreate | Öffnet eine bestehende Datei. Sollte diese im angegebenen Pfad nicht existieren, wird eine neue erzeugt.
Truncate | Öffnet eine Datei und löscht deren Inhalt. Nachfolgende Leseoperationen führen dazu, dass eine Ausnahme ausgelöst wird.
Der mode-Parameter beschreibt das Verhalten des Betriebssystems beim Öffnen einer Datei, gibt jedoch nicht an, was mit dem Inhalt der Datei geschehen soll. Soll er nur gelesen werden, oder möchte der Anwender in die Datei schreiben? Vielleicht sind auch beide Operationen gleichzeitig gewünscht. Diese Festlegung wird im Parameter access getroffen, der ebenfalls auf einer Aufzählung basiert – FileAccess. Diese hat nur drei Mitglieder: Read, Write und ReadWrite.

Tabelle 12.3 Die Konstanten der Enumeration »FileAccess«

FileAccess-Konstante | Beschreibung
Read | Datei wird für den Lesezugriff geöffnet.
Write | Datei wird für den Schreibzugriff geöffnet.
ReadWrite | Datei wird für den Lese- und Schreibzugriff geöffnet.
Eine Datei, die mit FileAccess.Read geöffnet wird, ist schreibgeschützt. Eine lesegeschützte Datei, deren Inhalt verändert werden soll, wird mit FileAccess.Write geöffnet. Die dritte Konstante FileAccess.ReadWrite beschreibt sowohl einen lesenden als auch einen schreibenden Zugriff. Kommen wir nun zum letzten Parameter der Open-Methode – share. Die Zeit der unabhängigen lokalen Rechner neigt sich schon seit Langem dem Ende zu, Netzwerke sind in den Unternehmen allgemeiner Standard. Infolgedessen muss ein Umstand Berücksichtigung finden, dem man bis vor einigen Jahren meist keine besondere Beachtung geschenkt hat: Mehrere Anwendungen oder mehrere Threads versuchen, gleichzeitig auf dieselbe Datei zuzugreifen. share beschreibt das Verhalten der Datei, wenn nach dem ersten Öffnen weitere Zugriffe auf die Datei erfolgen. Wie schon von den beiden vorher besprochenen Parametern bekannt ist, wird auch share durch Konstanten beschrieben, die einer Enumeration des Namespace System.IO zugerechnet werden – FileShare. Die Mitglieder ähneln denen der Enumeration FileAccess, werden aber um ein weiteres Mitglied ergänzt (genau genommen sind es zwei, aber das zweite spielt für uns keine Rolle).

Tabelle 12.4 Die Konstanten der Enumeration »FileShare«

FileShare-Konstante | Beschreibung
None | Alle weiteren Versuche, diese Datei zu öffnen, werden konsequent abgelehnt.
Read | Diese Datei darf von anderen Anwendungen oder Threads nur zum Lesen geöffnet werden.
Write | Diese Datei darf von anderen Anwendungen oder Threads nur zum Editieren geöffnet werden.
ReadWrite | Diese Datei darf von anderen Anwendungen oder Threads sowohl zum Lesen als auch zum Editieren geöffnet werden.
Damit haben wir die Parameterliste der Methode Open abgehandelt. Ihnen stehen alle Hilfsmittel zur Verfügung, um eine beliebige Datei unter bestimmten Voraussetzungen zu öffnen. Führen Sie sich aber vor Augen, dass eine geöffnete Datei nicht automatisch ihre Dateninformationen liefert oder sich manipulieren lässt. Diese Operationen haben mit dem Vorgang des Öffnens noch nichts zu tun, setzen ihn aber voraus. Beachten Sie in diesem Zusammenhang, dass Operationen, die den Inhalt einer Datei beeinflussen, auf dem zurückgegebenen Objekt vom Typ FileStream ausgeführt werden. In der folgenden Codezeile wird exemplarisch eine Datei mit Open geöffnet:
    FileStream stream = File.Open(@"C:\MyTestfile.txt",
        FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
Die Parameter besagen, dass die Datei MyTestfile.txt im Stammverzeichnis C:\ geöffnet werden soll – falls es dort eine solche Datei gibt. Wenn nicht, wird sie neu erzeugt. Der Inhalt der Datei lässt sich nach dem Öffnen sowohl lesen als auch ändern. Gleichzeitig werden weitere Zugriffe auf die Datei strikt unterbunden. #### Der einfachste Weg, in eine Datei zu schreiben und daraus zu lesen Um in eine Datei zu schreiben oder eine Datei zu lesen, waren bisher immer mehrere Codezeilen erforderlich. Eigentlich viel zu viel Aufwand, um eben schnell eine einfache Dateioperation auszuführen. Das .NET Framework wartet mit einer kaum vollständig zu beschreibenden Vielzahl an Möglichkeiten auf, die uns das Leben als Entwickler vereinfachen sollen. Besonders erwähnt werden sollen an dieser Stelle exemplarisch die Methoden ReadAllBytes, ReadAllLines und ReadAlltext zum Lesen und WriteAllBytes, WriteAllLines und WriteAllText zum Schreiben. Diese gehören zur Klasse File. Mit der simplen Anweisung
    File.WriteAllText(@"C:\MyTextFile.txt", text);
können Sie bereits den Inhalt der Variablen text in die angegebene Datei schreiben. Existiert die Datei schon, wird sie einfach überschrieben. Genauso einfach ist auch die inhaltliche Auswertung der Datei:
    Console.WriteLine(File.ReadAllText(@"C:\MyTextFile.txt"));
### 12.2.2 Die Klasse »FileInfo« Die ebenfalls nicht ableitbare Klasse FileInfo ist das Pendant zu der im vorigen Abschnitt beschriebenen Klasse File. Während File nur statische Methoden veröffentlicht, beziehen sich die Methoden der Klasse FileInfo auf eine konkrete Instanz. Um diese zu erhalten, steht nur ein Konstruktor zur Verfügung, dem Sie als Argument die Pfadangabe zu der Datei übergeben müssen, zum Beispiel:
    FileInfo myFile = new FileInfo(@"C:\MyDocuments\MyFile.txt");
Der Konstruktor prüft nicht, ob die Datei tatsächlich existiert. Bevor Sie Operationen auf dem Objekt ausführen, sollten Sie deshalb in jedem Fall vorher mit Exists sicherstellen, dass die Datei existiert.
    if (myFile.Exists) {
      // Datei existiert
    }
Während Exists in der Klasse File als Methode implementiert ist, der die Pfadangabe beim Aufruf übergeben werden muss, handelt es sich in der Klasse FileInfo um eine schreibgeschützte Eigenschaft des FileInfo-Objekts. #### Die Eigenschaften eines »FileInfo«-Objekts FileInfo veröffentlicht eine Reihe von Eigenschaften, denen der Zustand der Datei entnommen werden kann. So können Sie beispielsweise die Länge der Datei abfragen oder sich ein Objekt vom Typ Directory zurückgeben lassen (ein Directory-Objekt beschreibt ein Verzeichnis als Objekt, ähnlich wie FileInfo eine Datei beschreibt).

Tabelle 12.5 Die Eigenschaften eines Objekts vom Typ »FileInfo«

Eigenschaft | Beschreibung
Attributes | Ermöglicht das Setzen oder Auswerten der Dateiattribute (Hidden, Archive, ReadOnly usw.).
CreationTime | Liefert oder setzt das Erstellungsdatum der Datei.
Directory | Liefert eine Instanz des Verzeichnisses.
DirectoryName | Liefert eine Zeichenfolge mit der vollständigen Pfadangabe, jedoch ohne den Dateinamen.
Extension | Liefert die Dateierweiterung einschließlich des vorangestellten Punktes.
FullName | Gibt einen String mit der vollständigen Pfadangabe einschließlich des Dateinamens zurück.
LastAccessTime | Liefert oder setzt die Zeit des letzten Zugriffs auf die Datei.
LastWriteTime | Liefert oder setzt die Zeit des letzten schreibenden Zugriffs auf die Datei.
Length | Gibt die Länge der Datei zurück.
Name | Gibt den vollständigen Namen der Datei zurück.
Wir wollen uns aus Tabelle 12.5 die Eigenschaft Attributes genauer ansehen, die ihrerseits vom Typ FileAttributes ist. Attributes beschreibt ein Bitfeld bestimmter Größe. Jedes Attribut einer Datei wird durch Setzen eines bestimmten Bits in diesem Bitfeld beschrieben. Um festzustellen, ob ein Dateiattribut gesetzt ist, muss das Bitfeld, das alle Attribute beschreibt, mit dem gesuchten Dateiattribut bitweise &-verknüpft werden. Weicht das Ergebnis von der Zahl 0 ab, ist das Bit gesetzt. Dazu ein Zahlenbeispiel: Nehmen wir an, das Attribut XYZ würde durch die Bitkombination 0000 1000 (= 8) beschrieben und das Bitfeld würde aktuell 0010 1001 (= 41) enthalten. Um zu prüfen, ob das Attribut XYZ durch das Bitfeld beschrieben wird, gilt:
        0000 1000
    &   0010 1001
    --------------
    =   0000 1000
Das Ergebnis ist nicht 0 und daher so zu interpretieren, dass das Attribut im Bitfeld gesetzt ist. Um aus einer Datei ein bestimmtes Attribut herauszufiltern, beispielsweise Hidden, müssten wir daher wie folgt vorgehen:
    FileInfo f = new FileInfo(@"C:\Testfile.txt");
    if (0 != (f.Attributes & FileAttributes.Hidden)) {
      // Datei ist versteckt (hidden)
    }
Soll das Attribut gesetzt werden, bietet sich der ^-Operator an:
    f.Attributes = f.Attributes ^ FileAttributes.Hidden;
In gleicher Weise können Sie mit den Methoden GetAttributes und SetAttributes der Klasse File arbeiten. #### Die Methoden eines »FileInfo«-Objekts Die Klassen File und FileInfo sind sich in den Funktionalitäten, die dem Entwickler angeboten werden, sehr ähnlich: Es lassen sich Dateien löschen, verschieben, umbenennen, kopieren, öffnen usw. Die meisten geben ein Stream-Objekt für weitergehende Operationen zurück.

Tabelle 12.6 Die Methoden eines Objekts vom Typ »FileInfo«

Methode | Rückgabetyp | Beschreibung
AppendText | StreamWriter | Hängt Text an eine existierende Datei an.
CopyTo | FileInfo | Kopiert die Datei an einen anderen Speicherort.
Create | FileStream | Erzeugt eine Datei.
CreateText | StreamWriter | Erzeugt eine neue Textdatei.
Delete |  | Löscht die Datei.
Exists | Boolean | Gibt einen booleschen Wert zurück, der false ist, wenn die angegebene Datei nicht existiert.
MoveTo |  | Verschiebt die Datei in einen anderen Ordner oder benennt sie um.
Open | FileStream | Öffnet eine Datei.
OpenRead | FileStream | Öffnet eine Datei zum Lesen.
OpenText | StreamReader | Öffnet eine Textdatei zum Lesen.
OpenWrite | FileStream | Öffnet eine Datei zum Schreiben.
### 12.2.3 Die Klassen »Directory« und »DirectoryInfo« Die Klasse File veröffentlicht statische Methoden, um mit Dateien zu operieren, und die Klasse FileInfo beschreibt die Referenz auf ein konkretes Dateiobjekt. Ähnlich gestaltet sind die Klassen Directory und DirectoryInfo: Directory hat nur statische Methoden, und DirectoryInfo basiert auf einer konkreten Instanz. Es stellt sich natürlich sofort die Frage, warum die Architekten der Klassenbibliothek jeweils zwei Klassen mit nahezu gleichen Fähigkeiten vorgesehen haben. Der entscheidende Unterschied ist die Art und Weise, wie die Klassen im Hintergrund arbeiten. Zugriffe auf das Dateisystem setzen immer operative Berechtigungen voraus. Verfügt der Anwender nicht über die entsprechenden Rechte, wird die angeforderte Aktion abgelehnt. Die beiden Klassen File und Directory prüfen das bei jedem Zugriff erneut und belasten so das System unnötig, während die Überprüfung von den Klassen DirectoryInfo und FileInfo nur einmal ausgeführt wird. Mit Directory kann man Ordner anlegen, löschen oder verschieben, die in einem Verzeichnis physikalisch gespeicherte Dateinamen abrufen. Man kann mit Directory außerdem verzeichnisspezifische Eigenschaften sowie das Erstellungsdatum oder das Datum des letzten Zugriffs ermitteln. Tabelle 12.7 liefert einen Überblick über die Methoden von Directory.

Tabelle 12.7 Methoden der Klasse »Directory«

Methode | Beschreibung
CreateDirectory | Erzeugt ein Verzeichnis oder Unterverzeichnis.
Delete | Löscht ein Verzeichnis.
Exists | Überprüft, ob das angegebene Verzeichnis existiert.
GetCreationTime | Liefert das Erstellungsdatum samt Uhrzeit.
GetDirectories | Liefert die Namen aller Unterverzeichnisse eines spezifizierten Ordners.
GetFiles | Liefert alle Dateinamen eines spezifizierten Ordners zurück.
GetFileSystemEntries | Liefert die Namen aller Unterverzeichnisse und Dateien eines spezifizierten Ordners.
GetParent | Liefert den Namen des übergeordneten Verzeichnisses.
Move | Verschiebt ein Verzeichnis samt Dateien an einen neuen Speicherort.
SetCreationTime | Legt Datum und Uhrzeit eines Verzeichnisses fest.
Die Fähigkeiten der Klasse DirectoryInfo ähneln denen von Directory, setzen jedoch ein konkretes Objekt für den Zugriff auf die Elementfunktionen voraus. #### Beispielprogramm Im folgenden Beispielprogramm werden einige Methoden und Eigenschaften der Klassen File, FileInfo und Directory benutzt. Das Programm fordert den Anwender dazu auf, an der Konsole ein beliebiges Verzeichnis anzugeben, dessen Unterverzeichnisse und Dateien ermittelt und unter Angabe der Dateigröße und der Dateiattribute an der Konsole ausgegeben werden.
    // ------------------------------------------------------------
    // Beispiel: ...\Kapitel 12\FileDirectorySample
    // ------------------------------------------------------------
    class Program {
      public static void Main() {
        Program dirTest = new Program();
        FileInfo myFile;
        // Benutzereingabe anfordern
        string path = dirTest.PathInput();
        int len = path.Length;
        // alle Ordner und Dateien holen
        string[] str = Directory.GetFileSystemEntries(path);
        Console.WriteLine();
        Console.WriteLine("Ordner und Dateien im Verzeichnis {0}", path);
        Console.WriteLine(new string('-', 80));
        for (int i = 0; i <= str.GetUpperBound(0); i++) {
          // prüfen, ob der Eintrag ein Verzeichnis oder eine Datei ist
          if(0 == (File.GetAttributes(str[i]) & FileAttributes.Directory)) {
            // str(i) ist kein Verzeichnis
            myFile = new FileInfo(str[i]);
            string fileAttr = dirTest.GetFileAttributes(myFile);
            Console.WriteLine("{0,-30}{1,25} kB {2,-10} ",
                                        str[i].Substring(len - 1),
                                        myFile.Length / 1024,
                                        fileAttr);
          }
          else
                 Console.WriteLine("{0,-30}{1,-15}", str[i].Substring(len),
    			       "Dateiordner");
        }
        Console.ReadLine();
      }
      // Benutzer zur Eingabe eines Pfads auffordern
      string PathInput() {
        Console.Write("Geben Sie den zu durchsuchenden ");
        Console.Write("Ordner an: ");
        string searchPath = Console.ReadLine();
        // Wenn die Benutzereingabe als letztes Zeichen kein'\'
        // enthält, muss dieses angehängt werden.
        if(searchPath.Substring(searchPath.Length - 1) != "\\")
          searchPath += "\\";
        return searchPath;
      }
      // Feststellung, welche Dateiattribute gesetzt sind, und
      // Rückgabe eines Strings, der die gesetzten Attribute enthält
      string GetFileAttributes(FileInfo strFile) {
        string strAttr;
        // prüfen, ob das Archive-Attribut gesetzt ist
        if(0 != (strFile.Attributes & FileAttributes.Archive))
          strAttr = "A ";
        else
          strAttr = "  ";
        // prüfen, ob das Hidden-Attribut gesetzt ist
        if(0 != (strFile.Attributes & FileAttributes.Hidden))
          strAttr += "H ";
        else
          strAttr += "  ";
        // prüfen, ob das ReadOnly-Attribut gesetzt ist
        if(0 != (strFile.Attributes & FileAttributes.ReadOnly))
          strAttr += "R ";
        else
          strAttr += "  ";
        // prüfen, ob das System-Attribut gesetzt ist
        if(0 != (strFile.Attributes & FileAttributes.System))
          strAttr += "S ";
        else
          strAttr += "  ";
        return strAttr;
      }
    }
Wenn Sie die Anwendung starten, könnte die Ausgabe an der Konsole ungefähr so wie in Abbildung 12.2 aussehen. Hier klicken, um das Bild zu vergrößern Abbildung 12.2 Ausgabe des Beispiels »FileDirectorySample« Die komplette Anwendung ist in der Klasse Program realisiert. Die Klasse enthält neben der statischen Methode Main die Methoden PathInput und GetAttributes. Die Methode PathInput liefert eine Zeichenfolge zurück, die den Pfad des Verzeichnisses enthält, dessen Inhalt abgefragt werden soll. Wichtig ist im Kontext des Beispiels, die Rückgabezeichenfolge mit einem Backslash abzuschließen, da ansonsten die spätere Ausgabe an der Konsole nicht immer gleich aussieht. GetFileSystemEntries liefert als Ergebnis des Aufrufs ein String-Array, das dem Feld str zugewiesen wird.
    string str = Directory.GetFileSystemEntries(path);
Jedes Element des Arrays kann sowohl eine Datei- als auch eine Verzeichnisangabe enthalten. Daher wird in einer for-Schleife das Array vom ersten bis zum letzten Element durchlaufen, um festzustellen, ob das Element eine Datei oder ein Verzeichnis beschreibt. Handelt es sich um ein Verzeichnis, ist das Attribut Directory gesetzt. Mit
    if(0 == (File.GetAttributes(str[i]) & FileAttributes.Directory))
wird das geprüft. Die Bedingung liefert true, wenn eine Datei vorliegt. Nun folgt ein ganz entscheidender Punkt. Da das Programm die Größe der Datei ausgeben soll, können wir nicht mit File arbeiten, da in dieser Klasse keine Methode vorgesehen ist, die uns die Länge der Datei liefert. Dies ist nur über eine Instanz der Klasse FileInfo mit der Auswertung der schreibgeschützten Eigenschaft Length möglich, die bei jedem Schleifendurchlauf auf eine andere Datei verweist. Die benutzerdefinierte Methode GetAttributes dient dazu, das übergebene FileInfo-Objekt auf die Attribute Hidden, ReadOnly, Archive und System hin zu untersuchen. Aus dem Ergebnis wird eine Zeichenfolge zusammengesetzt, die den Anforderungen der Anwendung entspricht. Zum Schluss erfolgt noch die formatierte Ausgabe an der Konsole. Für den Verzeichnis- bzw. Dateinamen ist eine maximale Breite von 30 Zeichen vorgesehen. Ist dieser Wert größer, ist das Ergebnis eine zwar etwas unansehnliche Ausgabe, aber unseren Ansprüchen soll sie genügen. ### 12.2.4 Die Klasse »Path« Eine Pfadangabe beschreibt den Speicherort einer Datei oder eines Verzeichnisses. Die Schreibweise der Pfadangabe wird vom Betriebssystem vorgegeben und ist nicht auf allen Plattformen zwangsläufig identisch. Bei manchen Systemen muss die Pfadangabe mit dem Laufwerksbuchstaben beginnen, bei anderen Systemen ist das nicht unbedingt vorgeschrieben. Pfadangaben können sich auch auf Dateien beziehen. Es gibt Systeme, die ermöglichen als Dateierweiterung zur Beschreibung des Dateityps maximal drei Buchstaben, während andere durchaus mehr zulassen. Das sind nicht die einzigen Unterscheidungsmerkmale, die plattformspezifisch sind. Denken Sie nur an die Separatoren, mit denen zwei Verzeichnisse oder ein Verzeichnis von einer Datei getrennt werden. Windows-basierte Plattformen benutzen dazu das Zeichen Backslash (\), andere Systeme schreiben einen einfachen Slash (/) vor. #### Methoden der Klasse »Path« Alle Mitglieder der Klasse Path sind statisch und haben die Aufgabe, eine Pfadangabe in einer bestimmten Weise zu filtern. Sie benötigen daher keine Instanz der Klasse Path, um auf ein Feld oder eine Methode dieser Klasse zugreifen zu können.

Tabelle 12.8 Methoden der Klasse »Path«

Methode | Beschreibung
GetDirectoryName | Liefert aus einer gegebenen Pfadangabe das Verzeichnis zurück.
GetExtension | Liefert aus einer gegebenen Pfadangabe die Dateierweiterung einschließlich des führenden Punktes zurück.
GetFileName | Liefert den vollständigen Dateinamen zurück.
GetFileNameWithoutExtension | Liefert den Dateinamen ohne Dateierweiterung zurück.
GetFullPath | Liefert die komplette Pfadangabe zurück.
GetPathRoot | Liefert das Stammverzeichnis.
Beachten Sie dabei, dass keine dieser Methoden testet, ob die Datei oder das Verzeichnis tatsächlich existiert. Es werden lediglich die Zeichenkette und die Vorschriften der spezifischen Plattform zur Bestimmung des Ergebnisses herangezogen. Mit
    string strPath = @"C:\winnt\system\OLE2.dll"
liefern die Methoden die folgenden Rückgaben:
    Console.WriteLine(Path.GetPathRoot(strPath));
    // liefert C:\
    Console.WriteLine(Path.GetDirectoryName(strPath));
    // liefert C:\winnt\system
    Console.WriteLine(Path.GetFileNameWithoutExtension(strPath));
    // liefert OLE2
    Console.WriteLine(Path.GetFileName(strPath));
    // liefert OLE2.dll
    Console.WriteLine(Path.GetFullPath(strPath));
    // liefert C:\winnt\system\OLE2.dll
    Console.WriteLine(Path.GetExtension(strPath));
    // liefert .dll
#### Temporäre Verzeichnisse Sehr viele Anwendungen arbeiten mit Verzeichnissen, in die Dateien temporär, also nicht dauerhaft geschrieben werden. Die Klasse Path bietet mit GetTempPath eine Methode an, die das temporäre Verzeichnis des aktuell angemeldeten Benutzers liefert.
    public static string GetTempPath();
Unter Windows 7 ist dieses Verzeichnis standardmäßig unter dem Namen Temp in
    C:\Benutzer\<Username>\Local
zu finden. Mit GetTempFileName wird eine leere Datei im temporären Verzeichnis angelegt, der Rückgabewert ist die komplette Pfadangabe:
    public static string GetTempFileName();
Eine temporäre Datei kann von den anderen Methoden dazu benutzt werden, Zwischenergebnisse zu speichern, Informationen kurzfristig zu sichern und Abläufe zu protokollieren. Allerdings sollten Sie nicht vergessen, temporäre Dateien auch wieder zu löschen, wenn sie nicht mehr benötigt werden. ### 12.2.5 Die Klasse »DriveInfo« Mit DriveInfo können Sie herausfinden, welche Laufwerke verfügbar sind und um welchen Typ von Laufwerk es sich dabei handelt. Zudem können Sie mithilfe einer Abfrage die Kapazität und den verfügbaren freien Speicherplatz auf dem Laufwerk ermitteln.

Tabelle 12.9 Eigenschaften der Klasse »DriveInfo«

Eigenschaft | Rückgabetyp | Beschreibung
AvailableFreeSpace | long | Gibt die Menge an verfügbarem freiem Speicherplatz auf einem Laufwerk an.
DriveFormat | string | Ruft den Namen des Dateisystems ab.
DriveType | DriveType | Ruft den Laufwerkstyp ab.
IsReady | bool | Der Rückgabewert gibt an, ob das Laufwerk bereit ist.
Name | string | Liefert den Namen des Laufwerks.
RootDirectory | DirectoryInfo | Liefert das Stammverzeichnis des Laufwerks.
TotalFreeSpace | long | Liefert den verfügbaren Speicherplatz.
TotalSize | long | Ruft die Gesamtgröße des Speicherplatzes auf einem Laufwerk ab.
VolumeLabel | string | Ruft die Datenträgerbezeichnung eines Laufwerks ab.
Die Eigenschaft DriveType sollten wir uns noch etwas genauer ansehen. Sie liefert als Ergebnis des Aufrufs eine Konstante der gleichnamigen Enumeration ab. Diese hat insgesamt sieben Mitglieder, die Sie Tabelle 12.10 entnehmen können.

Tabelle 12.10 Mitglieder der Enumeration »DriveType«

Member | Beschreibung
CDRom | Optischer Datenträger (z. B. CD oder DVD)
Fixed | Festplatte
Network | Netzlaufwerk
NoRootDirectory | Das Laufwerk hat kein Stammverzeichnis.
Ram | RAM-Datenträger
Removable | Wechseldatenträger
Unknown | Unbekannter Laufwerkstyp
### 12.2.6 Die Klasse »SpecialDirectories« SpecialDirectories dient zur Ermittlung Windows-spezifischer Pfade, zum Beispiel des Pfads zu Eigene Bilder. Die Angaben werden über statische Eigenschaften als Zeichenfolge geliefert.

Tabelle 12.11 Mitglieder der Enumeration »DriveType«

Eigenschaft | Beschreibung
AllUserApplicationData | Ruft einen Pfadnamen ab, der auf die Anwendungsdaten im Verzeichnis \Dokumente und Einstellungen\All Users\Anwendungsdaten zeigt.
CurrentUserApplicationData | Ruft einen Pfadnamen ab, der auf das Verzeichnis Anwendungsdaten des aktuellen Benutzers zeigt.
Desktop | Ruft den Pfad des Desktop-Verzeichnisses ab.
MyDocuments | Ruft den Pfad des Eigene Dateien-Verzeichnisses ab.
MyMusic | Ruft den Pfad des Eigene Musik-Verzeichnisses ab.
MyPictures | Ruft den Pfad des Eigene Bilder-Verzeichnisses ab.
ProgramFiles | Ruft den Pfad des Program Files-Verzeichnisses ab.
Programs | Ruft den Pfad des Programme-Verzeichnisses ab.
Temp | Ruft den Pfad des Temp-Verzeichnisses ab.