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 FACHBUCHHANDLUNGCARL HANSER VERLAG
Walter Doberenz, Thomas Kowalski
Programmieren lernen in Visual C#.NET
3-446-22023-2
www.hanser.de8.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 anzeigen8.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öscht208 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 Abbildung8.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