Dateien und Streams: FileStream
Die FileStream-Klasse ist eine Klasse, mit welcher eine Datei gelesen oder geschrieben werden kann. Hierbei ist es im Gegensatz zu den einfachen Funktionen der statischen File-Klasse möglich, die Datei in mehreren Einzelschritten zu schreiben oder zu lesen, ohne die Datei währenddessen zu schließen. Beim Schreiben und Lesen von einem FileStream werden einzelne Bytes verarbeitet, d. h. eine Zeichenkette muss erst in ein byte-Array konvertiert werden bevor dieses geschrieben werden kann. Deshalb wird auch von einem Stream gesprochen.
Ein Stream muss als erstes geöffnet werden, bevor Daten gelesen oder geschrieben werden können. In C# existieren solche Funktionen zum Öffnen meistens nicht, da das Öffnen bereits beim Erstellen des Objekts erfolgt. Nach dem Dateizugriff ist es notwendig, den Stream wieder zu schließen. Hierfür gibt es die Funktion Close(). Im Beispiel haben wir einen try-catch-finally-Block eingesetzt, welcher gerne bei solchen Dateizugriffen eingesetzt wird.
In den nächsten Abschnitten wollen wir nun genauer auf die FileStream-Klasse selbst eingehen. Der Konstruktor der Klasse ist mehrfach überladen und wird oftmals mit drei Parametern aufgerufen: Hierbei ist der erste Parameter der Dateiname, der zweite Parameter der Öffnungs-Modus und der letzte Parameter der Zugriffs-Modus. Beim Öffnungs-Modus können wir angeben, ob wir die Datei erstellen (CreateNew), erstellen oder überschreiben (CreateNew), öffnen (Open), öffnen oder erstellen (OpenOrCreate) oder Daten anhängen (Append) wollen. Hier wird die Enumeration FileMode verwendet. Mit der Enumeration FileAccess können wir den Zugriffs-Modus angeben: lesen (Read), schreiben (Write) oder lesen und schreiben (ReadWrite). Die Datei im selben Moment zu lesen und zu schreiben, ist eher untypisch und wird nur selten benötigt.
Um die Datei schreiben zu können, gibt es die Funktionen WriteByte() und Write(). WriteByte() schreibt ein einzelnes Byte und erwartet dieses als Parameter. Die Write()-Funktion schreibt ein ganzes Byte-Array bzw. einen Teil davon. Die Funktion erwartet als Parameter ein Byte-Array, ein Offset (Index im Byte-Array, ab welchem geschrieben werden soll, zumeist 0) und die Länge (der zu schreibenden Bytes). Zum Lesen gibt es die Funktionen ReadByte() und Read(). Die ReadByte()-Funktion erwartet keine Parameter und gibt lediglich ein einzelnes Byte zurück. Die Read()-Funktion ist vom Aufbau identisch zur Write()-Funktion.
Um innerhalb einer Datei springen zu können, gibt es die Funktion Seek(), welche den sogenannten Lese- bzw. Schreibzeiger der Datei setzt. Die Funktion erwartet zwei Parameter: Die Position und die Positionierungs-Art (Enumeration SeekOrigin). Bei der Angabe der Positionierungs-Art können Sie angeben, von wo aus der Dateizeiger an Hand des ersten Parameters gesetzt werden soll: Begin (ab dem Anfang der Datei), Current (ab der aktuellen Position) und End (ab dem Ende der Datei, hierbei sollte der erste Parameter einen negativen Wert aufweisen).
Am Ende des Dateizugriffs sollte die Datei / der Stream stets geschlossen werden. Hierfür ist die Funktion Close() zuständig, welche zudem auch den Inhalt einer Datei aus dem internen Datenpuffer schreibt und diesen anschließend leert. Um das Schreiben der Daten manuell auszuführen, können Sie die Funktion Flush() aufrufen, welche kein Parameter zur Übergabe benötigt. Meistens ist dieser Aufruf jedoch nicht notwendig.
Im Beispiel wird eine Zeichenkette über die Klasse Encoding in ein Byte-Array umgewandelt. Dabei muss die Zeichenkodierung (im Beispiel ASCII) angegeben werden.
Program.cs
const string sDateiname = "test.txt"; const string sInhalt = "Hallo Welt!"; FileStream oStream = null; try { oStream = new FileStream(sDateiname, FileMode.OpenOrCreate, FileAccess.Write); oStream.Write(Encoding.ASCII.GetBytes(sInhalt), 0, sInhalt.Length); Console.WriteLine("Die Datei {0} ist nun {1} Bytes groß!", sDateiname, oStream.Length); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } finally { // mit Close() werden die Daten automatisch geschrieben und die Datei geschlossen, wir könnten // auch Flush() aufrufen, um die Datei manuell zu schreiben if (oStream != null) oStream.Close(); } Console.ReadKey();