Programmieren lernen in Visual C#.NET
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
Programmieren lernen in Visual C#.NET von Walter Doberenz, Thomas Kowalski 1. Auflage Hanser München 2003 Verlag C.H. Beck im Internet: www.beck.de ISBN 978 3 446 22023 2 Zu Inhaltsverzeichnis schnell und portofrei erhältlich bei beck-shop.de DIE FACHBUCHHANDLUNG
CARL HANSER VERLAG Walter Doberenz, Thomas Kowalski Programmieren lernen in Visual C#.NET 3-446-22023-2 www.hanser.de
8.1 Operationen mit Verzeichnissen und Dateien 201 Zu den wichtigsten Aufgaben des Programmierers zählt es, Daten auf der Festplatte (Diskette, CD, ...) permanent abzuspeichern bzw. von dort zu laden. Das .NET-Framework stellt dafür im System.IO-Namensraum eine Anzahl leistungsfähiger Klassen zur Verfügung, die diese Aufgabe vereinfachen sollen. Diese Lektion vermittelt Ihnen die dazu erforderlichen Grundkenntnisse. 8.1 Operationen mit Verzeichnissen und Dateien Bevor wir uns dem Lesen und Schreiben von Dateien zuwenden, betrachten wir die Arbeit auf Ver- zeichnisebene, womit das Erstellen, Löschen, Kopieren, Verschieben, Umbenennen, Durchsuchen und Überwachen von Verzeichnissen und Dateien gemeint ist. 8.1.1 Klassen für Verzeichnis- und Dateioperationen Für Manipulationen mit Verzeichnissen und Dateien gibt es neben der Path-Klasse die Pärchen Directory/DirectoryInfo und File/FileInfo, die sich vor allem hinsichtlich ihrer Instanziierbarkeit unterscheiden (statische oder Instanzen-Methoden, siehe 8.1.11). Alle fünf Klassen befinden sich im System.IO-Namensraum. Klasse Beschreibung Directory ... die statischen Methoden erlauben das Erstellen, Verschieben und Benennen von Verzeichnissen und Unterverzeichnissen. DirectoryInfo ... ähnelt der Directory-Klasse, enthält aber nur Instanz-Methoden. Path ... die statischen Methoden erlauben die plattformübergreifende Arbeit mit Verzeichnissen. File ... die statischen Methoden erlauben das Erzeugen, Kopieren, Löschen, Verschieben und Öffnen von Dateien. FileInfo ... ähnelt der File-Klasse, enthält aber nur Instanz-Methoden. FileSystemWatcher ... löst Ereignisse zum Überwachen des Dateisystems aus. Hinweis: Methoden der Klassen File und FileInfo liefern auch die Voraussetzungen für den Schreib- und Lesezugriff auf Dateien (siehe 8.2). Bevor wir uns der Anwendung dieser Klassen zuwenden, soll im folgenden Abschnitt noch ein generelles Problem geklärt werden. 8.1.2 Zur Schreibweise von Verzeichnissen in C# Eine "normale" Schreibweise von Verzeichnissen, wie z.B. "c:\temp", ist in C# nicht möglich, da der Slash (\ bzw. /) als Steuerzeichen (Escape-Sequenz) gedeutet wird. Generell gibt es deshalb zwei Alternativen: ■ Verwenden des doppelten Slash, z.B. "c://temp" ■ Voranstellen des Zeichens "@", z.B. @"c:/temp"
202 LEKTION 8: Dateien und Streams Hinweis: Ob der normale Slash (/) oder der Backslash (\) verwendet wird, ist bedeutungslos. 8.1.3 Verzeichnisse erzeugen und löschen Mit Directory-Klasse Die einfachsten Möglichkeiten zum Erzeugen und Löschen von Verzeichnissen bieten die statischen Methoden CreateDirectory() und Delete() der Directory-Klasse. Beispiel: Ein Verzeichnis erzeugen und anschließend wieder löschen string path=@"c:\temp"; Directory.CreateDirectory(path); // falls Verzeichnis bereits vorhanden, passiert nichts! ... Directory.Delete(path,true); // löscht auch vorhandene Unterverzeichnisse und Dateien Mit DirectoryInfo-Klasse Das gleiche Ziel, allerdings etwas umständlicher, erreicht man mit der Create-Methode der DirectoryInfo-Klasse, wobei mittels CreateSubdirectory auch das Hinzufügen von Unterverzeich- nissen möglich ist. Beispiel: Es werden ein Verzeichnis und ein Unterverzeichnis angelegt und anschließend wieder gelöscht. DirectoryInfo di = new DirectoryInfo(@"c:\temp"); di.Create(); di.CreateSubdirectory("temp1"); ... di.Delete(true); // löscht inklusive vorhandener Unterverzeichnisse und Dateien Hinweis: Der parameterlose Aufruf von Delete() funktioniert nur, wenn das Verzeichnis leer ist! 8.1.4 Verzeichnisse verschieben und umbenennen Für diese Aufgaben verwenden Sie am besten die Move-Methode der statischen Directory-Klasse. Beispiel: Das Verzeichnis c:\tempX wird verschoben und umbenannt nach c:\beispiele\tempY. Directory.Move(@"c:\tempX", @"c:\beispiele\tempY"); 8.1.5 Das aktuelle Verzeichnis ermitteln bzw. festlegen Verwenden Sie dazu die GetCurrentDirectory- bzw. SetCurrentDirectory-Methode der (statischen) Directory-Klasse.
8.1 Operationen mit Verzeichnissen und Dateien 203 Beispiel: Festlegen und Anzeigen des aktuellen Arbeitsverzeichnisses Directory.SetCurrentDirectory(@"c:/test"); label1.Text = Directory.GetCurrentDirectory(); // zeigt "c:/test" Hinweis: Wenn der Dateiname ohne Pfad angegeben wird, bezieht sich die Datei automatisch auf das Projekt- bzw. Arbeitsverzeichnis. Beispiel: Im Projektverzeichnis wird ein Verzeichnis \temp angelegt. Directory.CreateDirectory("temp"); 8.1.6 Unterverzeichnisse ermitteln Um alle Unterverzeichnisse zu ermitteln, verwenden Sie die GetDirectories-Methode der Directory- Info-Klasse. Beispiel: Es werden alle Unterverzeichnisse von c:\ in einer ListBox angezeigt. DirectoryInfo myDir = new DirectoryInfo(@"c:\"); // Erzeugen eines neuen DirectoryInfo-Objekts DirectoryInfo[] myDirs; // Array zum Speichern der Unterverzeichnisse anlegen myDirs = myDir.GetDirectories(); // alle Unterverzeichnisse ermitteln und im Array abspeichern for (int i = 0; i < myDirs.Length; i++) // alle Unterverzeichnisse durchlaufen ... { listBox1.Items.Add(myDirs[i].Name); // ... und Verzeichnisnamen zur ListBox hinzufügen } Hinweis: Mit der GetFiles-Methode können Sie alle in einem Verzeichnis enthaltenen Dateien bestimmen. Das komplette Beispiel finden Sie auf der Buch-CD. 8.1.7 Anwenden der Path-Klasse Die Anwendung der Methoden der statischen Path-Klasse soll anhand eines Beispiels demonstriert werden. Beispiel: Ausgabe von Dateiinfos in einer ListBox string verz = @"c:\test\info.txt"; listBox1.Items.Add("Verzeichnis : " + Path.GetDirectoryName(verz)); listBox1.Items.Add("Dateiname : " + Path.GetFileName(verz)); listBox1.Items.Add("Dateiname ohne Extension : " + Path.GetFileNameWithoutExtension(verz)); listBox1.Items.Add("Dateiextension : " + Path.GetExtension(verz)); listBox1.Items.Add("Rootverzeichnis : " + Path.GetPathRoot(verz));
204 LEKTION 8: Dateien und Streams listBox1.Items.Add("Temporäres Verzeichnis : " + Path.GetTempPath()); listBox1.Items.Add("Neues Tempfile : " + Path.GetTempFileName()); Hinweis: Die meisten Member der Path-Klasse wirken nicht mit dem Dateisystem zusammen und überprüfen deshalb nicht, ob die durch eine Pfadzeichenfolge angegebene Datei tatsächlich vorhanden ist. 8.1.8 Dateien kopieren, verschieben und umbenennen Kopieren und verschieben Am einfachsten realisieren Sie diese Aufgabe mit den statischen Copy- bzw. Move-Methoden der File-Klasse. Beispiel: Datei kopieren und anschließend verschieben string sourcePath=@"c:\sample.txt"; string destPath=@"c:\sample1.txt"; string movePath=@"c:\temp\sample1.txt"; File.Copy(sourcePath,destPath); File.Move(sourcePath,movePath); Falls Sie lieber mit Instanzen arbeiten, können Sie die Methoden CopyTo und MoveTo der Klassen FileInfo bzw. DirectoryInfo verwenden. Hinweis: Auch die Directory-Klasse verfügt über eine Move-Methode zum Verschieben von Verzeichnissen. Umbenennen Das .NET-Framework bietet keine Möglichkeit zum direkten Umbenennen einer Datei, da die Name-Eigenschaft der FileInfo-Klasse schreibgeschützt ist und eine Rename-Methode fehlt. Verwenden Sie zum Umbenennen also die Methoden Move der Klasse File bzw. MoveTo der Klasse FileInfo. Beispiel: Umbenennen der Datei info.txt in info_1.txt FileInfo fi = new FileInfo(@"c:\test\info.txt"); fi.MoveTo(@"c:\test\info_1.txt");
8.1 Operationen mit Verzeichnissen und Dateien 205 8.1.9 Dateiattribute feststellen FileAttributes-Enumeration Die verschiedenen Attribute für Dateien und Verzeichnisse sind in der FileAttribute-Enumeration anzutreffen. Die Tabelle zeigt die wichtigsten: Mitglied Beschreibung Archive ... entspricht dem Archiv-Status der Datei, wie er oft zum Markieren einer zu löschenden oder einer Backup-Datei verwendet wird. Compressed ... entspricht einer gepackten Datei. Directory ... zeigt an, dass die Datei in Wirklichkeit ein Verzeichnis ist. Encrypted ... die Datei ist verschlüsselt. Hidden ... die Datei ist versteckt und demzufolge in einem gewöhnlichen Verzeichnis unsichtbar. Normal ... es wurden keine Datei-Attribute gesetzt. ReadOnly ... die Datei kann nicht verändert, sondern nur gelesen werden. System ... die Datei gehört zum Betriebssystem oder wird exklusiv von diesem benutzt. Temporary ... die Datei ist temporär, d.h., sie wird vom Programm bei Bedarf angelegt und wieder gelöscht. Wichtige Eigenschaften und Methoden Um die Dateiattribute zu ermitteln, kann man entweder auf die Eigenschaften der FileInfo-Klasse oder aber auch auf die entsprechenden (statischen) Methoden der File-Klasse zugreifen: Eigenschaft Methode Beschreibung FileInfo-Klasse File-Klasse Attributes GetAttributes() ... Wert basiert auf Datei-Attribute-Flags SetAttributes() (archive, compressed, directory, hidden, ...) . CreationTime GetCreationTime() ... Datum/Zeit der Erstellung. SetCreationTime() LastAccessTime GetLastAccessTime() ... Datum/Zeit des letzten Zugriffs. SetLastAccessTime() LastWriteTime GetLastWriteTime() ... Datum/Zeit des letzten Schreibzugriffs. SetLastWriteTime() Exists Exists() ... liefert true, falls Datei physikalisch existiert. Beispiel: Feststellen, ob Datei im Arbeitsverzeichnis existiert if (File.Exists("liesmich.txt")) MessageBox.Show("Datei ist vorhanden!");
206 LEKTION 8: Dateien und Streams oder FileInfo fi = new FileInfo("liesmich.txt"); if (fi.Exists) MessageBox.Show("Datei ist vorhanden!"); Beispiel: Anzeige des Erstellungsdatums einer Datei label1.Text = File.GetCreationTime("liesmich.txt").ToString(); Beispiel: In zwei CheckBoxen wird angezeigt, ob es sich um eine normale oder um eine Archiv- Datei handelt. FileAttributes attbs = File.GetAttributes("c://beispiele//test.dat"); if (attbs==(attbs|FileAttributes.Normal)) checkBox1.Checked = true; else checkBox1.Checked = false; if (attbs==(attbs|FileAttributes.Archive)) checkBox2.Checked = true; else checkBox2.Checked = false; Das komplette Beispiel finden Sie in Übung 8.1. 8.1.10 Weitere Datei-Eigenschaften Die folgende Tabelle zeigt einige weitere wichtige Eigenschaften der FileInfo-Klasse. Eigenschaft Beschreibung FileInfo-Klasse Directory ... liefert Instanz des übergeordneten Verzeichnisses. DirectoryName ... liefert den vollständigen Dateipfad. Extension ... liefert Dateiextension (z.B. txt für Textdateien). FullName ... liefert vollständigen Dateipfad plus Dateinamen. Length ... liefert Dateigröße in Bytes. Name ... liefert Dateinamen. Beispiel: Der Pfad der Datei liesmich.txt wird in einem Label angezeigt. FileInfo fi = new FileInfo("liesmich.txt"); label1.Text = fi.DirectoryName; Im Zusammenhang mit der Directory-Eigenschaft der FileInfo-Klasse verdient die GetFileSystem- Infos-Methode der DirectoryInfo-Klasse besondere Beachtung. Beispiel: In einer TextBox werden neben dem Verzeichnis einer Datei alle weiteren sich im gleichen Verzeichnis befindlichen Dateien und Unterverzeichnisse angezeigt. FileInfo fi = new FileInfo("liesmich.txt"); // öffnet existierende Datei oder erzeugt neue DirectoryInfo di = fi.Directory; // Verzeichnis-Instanz erzeugen FileSystemInfo[] fsi = di.GetFileSystemInfos(); // alle Einträge ermitteln textBox1.Text = di.FullName + Environment.NewLine; // vollständigen Verzeichnispfad anzeigen
8.1 Operationen mit Verzeichnissen und Dateien 207 foreach (FileSystemInfo info in fsi) // ... dann alle weiteren Unterverzeichnisse und Dateien textBox1.Text += info.Name + Environment.NewLine; 8.1.11 Statische oder Instanzen-Klasse? Wenn Sie mit den Methoden der statischen Klassen File, Directory und Path arbeiten, werden Sicherheitsüberprüfungen bei jedem Methodenaufruf vorgenommen, bei den Instanzen-Methoden der Klassen FileInfo und DirectoryInfo geschieht dies nur ein einziges Mal. Bei statischen Methoden müssen Sie jeder Methode den Dateinamen oder den Verzeichnispfad übergeben. Das kann dann ziemlich lästig werden, wenn Sie diese Methoden öfters hintereinander aufrufen müssen. Die entsprechenden Eigenschaften der Instanzen-Klassen FileInfo und Directory- Info hingegen erlauben es Ihnen, den Datei- oder Verzeichnisnamen bereits im Konstruktor einmalig zu spezifizieren. Beispiel: Zwei alternative Möglichkeiten zum Anzeigen von Erstellungsdatum und Zeitpunkt des letzten Zugriffs auf die Datei c:\test\info.txt label1.Text = File.GetCreationTime(@"c:\test\info.txt").ToString(); label2.Text = File.GetLastAccessTime(@"c:\test\info.txt").ToString(); oder FileInfo myFile = new FileInfo(@"c:\test\info.txt"); label1.Text = myFile.CreationTime.ToString(); label2.Text = myFile.LastAccessTime.ToString(); Hinweis: In einigen Fällen haben Sie nur eine Wahl, wenn die gewünschte Eigenschaft/Methode nur von einer Klasse angeboten wird. 8.1.12 Überwachung von Änderungen im Dateisystem Die Klasse FileSystemWatcher dient dem einfachen Beobachten des Dateisystems, so löst sie z.B. Ereignisse aus, wenn Dateien oder Verzeichnisse geändert werden. Beispiel: Das Überwachen von vier Ereignissen von .txt-Dateien im Verzeichnis c:\Beispiele: FileSystemWatcher watcher = new FileSystemWatcher(@"C:\Beispiele"); watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.FileName; watcher.Filter = "*.txt"; watcher.Changed += new FileSystemEventHandler(OnChanged); // Datei wurde geändert watcher.Created += new FileSystemEventHandler(OnChanged); // Datei wurde neu hinzugefügt watcher.Deleted += new FileSystemEventHandler(OnChanged); // Datei wurde gelöscht
208 LEKTION 8: Dateien und Streams watcher.Renamed += new RenamedEventHandler(OnRenamed); // Datei wurde umbenannt watcher.EnableRaisingEvents = true; // Start der Überwachung Die beiden Event-Handler spezifizieren die Reaktion auf die vier Ereignisse (in unserem Fall erfolgt eine Anzeige in einer ListBox): public void OnChanged(object source, FileSystemEventArgs e) { listBox1.Items.Add("Datei: " + e.FullPath + " " + e.ChangeType); } public void OnRenamed(object source, RenamedEventArgs e) { listBox1.Items.Add("Datei: " + e.OldFullPath + " umbenannt in " + e.FullPath); } Hinweis: Das vollständige Programm finden Sie auf der Buch-CD. 8.2 Lesen und schreiben von Dateien In diesem Abschnitt geht es um das zentrale Anliegen der Lektion, nämlich um das Abspeichern von Daten. Die wichtigsten Dateitypen sind: ■ Textdatei ■ Binärdatei (Bilddateien etc.) ■ sequenzielle Datei ■ Random-Access-Datei Hinweis: Da .NET keine typisierten Dateien unterstützt, müssen sequenzielle und Random- Access-Dateien durch geeignete Programmiermaßnahmen auf Binärdateien zurückge- führt werden. 8.2.1 Übersicht Dateien und Streams Während man die in einer Datei gespeicherten Informationen auch als persistente Daten bezeichnet, arbeitet das Programm mit temporären bzw. transienten Daten. Wie Sie der folgenden Abbildung
8.2 Lesen und schreiben von Dateien 209 entnehmen, gewährleisten Streams quasi als "Verbindungskanäle" die Kommunikation zwischen Datei und Programm. Programm temporäre Daten (Arbeitsspeicher) Stream Stream Read Write persistente Daten Datei (Festplatte) Klassen Auch für Datei- und Stream-Operationen werden zunächst die Klassen File bzw. FileInfo benötigt (siehe Abschnitt 8.1). Die folgende Tabelle zeigt die weiteren wichtigen Klassen. Klasse Beschreibung FileStream ... erlaubt, basierend auf einer Datei, das Erstellen einer Stream-Instanz. StreamReader ... implementiert ein TextReader-Objekt, welches Zeichen von einem Byte- Stream in einer bestimmten Kodierung liest. StreamWriter ... implementiert ein TextWriter-Objekt, welches Zeichen in einen Stream in einer speziellen Kodierung liest. StringReader ... implementiert ein TextReader-Objekt, das Daten von einem String liest. StringWriter ... implementiert ein TextWriter-Objekt, das Daten in einen String schreibt. Die Daten werden in einer darunter liegenden StringBuilder-Klasse gespeichert. BinaryReader ... erlaubt das binäre Lesen von Dateien. BinaryWriter .. erlaubt das binäre Schreiben in Dateien. BinaryFormatter ...kann Objekte in einen Stream serialisieren bzw. von dort deserialisieren. Erzeugen einer Stream-Instanz Voraussetzung für jeglichen Dateizugriff ist das Vorhandensein eines Stream-Objekts (siehe obige Abbildung). Letzteres kann entweder über die Open-Methode eines FileInfo-Objekts oder der statischen File-Klasse erzeugt werden. Beispiel: Die Datei temp.txt soll für den exklusiven Schreib-/Lesezugriff geöffnet werden. Falls sie nicht vorhanden ist, wird sie neu erzeugt. FileInfo fi = new FileInfo("temp.txt"); FileStream fs = fi.Open( FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None );
210 LEKTION 8: Dateien und Streams oder FileStream fs = File.Open("temp.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); Zur Bedeutung der einzelnen Parameter der Open-Methode kommen wir im folgenden Abschnitt. 8.2.2 Dateiparameter In den Konstruktoren der Klassen File, FileInfo und FileStream werden bestimmte Parameter übergeben, die in Enumerationen (Enums bzw. Aufzählungstypen) gekapselt sind. FileAccess Diese Enumeration bezeichnet den Zugriffslevel auf eine Datei. Mitglied Beschreibung Read ... erlaubt Lesezugriff ReadWrite ... erlaubt Lese- und Schreibzugriff Write ... erlaubt Schreibzugriff Die FileMode-Enumeration Diese Enumeration bestimmt den Öffnungsmodus einer Datei. Mitglied Beschreibung Append Eine existierende Datei wird geöffnet und der Dateizeiger an das Ende bewegt, oder eine neue Datei wird erstellt ( FileAccess.Write ist erforderlich, Lesever- suche schlagen fehl). Create Eine neue Datei wird erzeugt. Falls die Datei bereits existiert, wird sie überschrieben. Open Eine existierende Datei wird geöffnet. OpenOrCreate Falls die Datei existiert, wird sie geöffnet, andernfalls wird sie neu erzeugt. Truncate Eine existierende Datei wird geöffnet und die Dateigröße auf null Bytes beschnitten. Die FileShare-Enumeration Diese Enumeration verwenden Sie, um festzulegen, ob auf eine Datei gleichzeitig von mehreren Prozessen aus zugegriffen werden kann. Mitglied Beschreibung None Die Datei ist für den gleichzeitigen Zugriff gesperrt. Alle weiteren Anforderungen zum Öffnen werden abgelehnt, es sei denn, die Datei ist geschlossen. Read Auch andere Benutzer bzw. Prozesse dürfen die Datei lesen. Versuche zum Schreiben bzw. Abspeichern schlagen fehl.
Sie können auch lesen