Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 12 Arbeiten mit Dateien und Streams
Pfeil 12.1 Einführung
Pfeil 12.2 Namespaces der Ein- bzw. Ausgabe
Pfeil 12.2.1 Das Behandeln von Ausnahmen bei E/A-Operationen
Pfeil 12.3 Laufwerke, Verzeichnisse und Dateien
Pfeil 12.3.1 Die Klasse »File«
Pfeil 12.3.2 Die Klasse »FileInfo«
Pfeil 12.3.3 Die Klassen »Directory« und »DirectoryInfo«
Pfeil 12.3.4 Die Klasse »Path«
Pfeil 12.3.5 Die Klasse »DriveInfo«
Pfeil 12.4 Die »Stream«-Klassen
Pfeil 12.4.1 Die abstrakte Klasse »Stream«
Pfeil 12.4.2 Die von »Stream« abgeleiteten Klassen im Überblick
Pfeil 12.4.3 Die Klasse »FileStream«
Pfeil 12.5 Die Klassen »TextReader« und »TextWriter«
Pfeil 12.5.1 Die Klasse »StreamWriter«
Pfeil 12.5.2 Die Klasse »StreamReader«
Pfeil 12.6 Die Klassen »BinaryReader« und »BinaryWriter«
Pfeil 12.6.1 Komplexe binäre Dateien

Rheinwerk Computing - Zum Seitenanfang

12.5 Die Klassen »TextReader« und »TextWriter«Zur nächsten Überschrift

Wie Sie in den vorhergehenden Abschnitten gesehen haben, stellt die Klasse Stream Operationen bereit, mit denen Sie unformatierte Daten byteweise lesen und schreiben können. Stream-Objekte bieten sich daher insbesondere für allgemeine Operationen an, beispielsweise für das Kopieren von Dateien. Die Klasse Stream beziehungsweise die daraus abgeleiteten Klassen sind aber weniger gut für textuelle Ein- und Ausgabeoperationen geeignet.

Um den üblichen Anforderungen von Textoperationen zu entsprechen, stellt die .NET-Klassenbibliothek die beiden abstrakten Klassen TextReader und TextWriter bereit. Objekte, die aus der Klasse Stream abgeleitet werden, unterstützen den vollständigen Satz an E/A-Operationen, also sowohl das Lesen als auch das Schreiben. Nun wird die Bearbeitung auf zwei Klassen aufgeteilt, die entweder nur lesen oder nur schreiben können.

Abbildung

Abbildung 12.4 Objekthierarchie der »Reader«- und »Writer«-Klassen

TextReader und TextWriter sind abstrakt definiert und müssen daher abgeleitet werden. Das .NET Framework bietet solche Ableitungen mit StreamReader und -Writer sowie StringReader und -Writer an. Von TextWriter gibt es auch noch weitere, spezialisierte Ableitungen. Im Folgenden werden wir uns mit den Klassen StreamReader und StreamWriter beschäftigen.


Rheinwerk Computing - Zum Seitenanfang

12.5.1 Die Klasse »StreamWriter«Zur nächsten ÜberschriftZur vorigen Überschrift

Die Konstruktoren der Klasse »StreamWriter«

Wir werden uns daher zunächst einigen Konstruktoren der Klasse StreamWriter zuwenden, um zu sehen, auf welcher Basis sich ein Objekt dieses Typs erzeugen lässt.

public StreamWriter(Stream);
public StreamWriter(string);
public StreamWriter(Stream, Encoding);
public StreamWriter(string, bool);
public StreamWriter(Stream, Encoding, int);
public StreamWriter(string, bool, Encoding);
public StreamWriter(string, bool, Encoding, int);

Es fällt zunächst auf, dass wir jedem Konstruktor entweder eine Zeichenfolge oder ein Objekt vom Typ Stream übergeben müssen. Entscheiden wir uns für eine Zeichenfolge, enthält diese die Pfadangabe zu einer Datei.

Da die Klasse Stream abstrakt ist, können wir natürlich keine Referenz auf ein konkretes Stream-Objekt übergeben. Aber die Klasse Stream wird abgeleitet, beispielsweise von FileStream. Die Referenz auf ein Objekt einer aus Stream abgeleiteten Klasse gilt aber nach den Paradigmen der Objektorientierung gleichzeitig als ein Objekt vom Typ der Basisklasse. Also kann dem Parameter im Konstruktor, der den Typ Stream erwartet, ein Objekt vom Typ einer aus Stream abgeleiteten Klasse übergeben werden.

Nun sehen wir uns natürlich sofort mit der Frage konfrontiert, welchen Sinn es hat, ein Stream-Objekt als Argument an den Konstruktor zu übergeben. Wie Sie sich vielleicht noch erinnern, werden die Stream-Objekte generell in zwei Typen klassifiziert: in Base-Streams und Pass-Through-Streams. Ein Base-Stream endet zum Beispiel direkt in einer Datei oder in einer Netzwerkverbindung, ein Pass-Through-Stream ist ein »Durchlaufobjekt«, das die Fähigkeiten eines Base-Streams erweitert.

Betrachten wir zunächst den Konstruktor der Klasse StreamWriter, der in einem String eine Pfadangabe entgegennimmt:

public StreamWriter(string);

Ein Objekt, das basierend auf dieser Erstellungsroutine instanziiert wird, weiß, wohin die Daten geschrieben werden – nämlich in die Datei, die durch das String-Argument beschrieben wird, z. B.:

StreamWriter myStreamWriter = new StreamWriter(@"D:\MyText.txt");

Wir erzeugen mit dieser Anweisung einen Base-Stream, der die Daten – genauer gesagt eine Zeichenfolge – in eine Datei schreiben kann. Nun wollen wir ein anderes StreamWriter-Objekt erzeugen, diesmal allerdings auf Basis der Übergabe eines FileStream-Objekts.

FileStream fs = new FileStream(@"D:\Test.txt", FileMode.CreateNew);
StreamWriter myStreamWriter = new StreamWriter(fs);

In der ersten Anweisung wird ein Objekt vom Typ FileStream erstellt, das eine neue Datei namens Test.txt in der Root D:\ erzeugt. Dieses Objekt wird seinerseits als Argument an den Konstruktor der Klasse StreamWriter übergeben. Als Resultat liegt eine Hintereinanderschaltung von zwei Stream-Objekten vor, woraus sich Nutzen ziehen lässt. Wie Sie wissen, schreiben und lesen Objekte, die auf der Stream-Klasse basieren, nur elementare Bytes. Demgegenüber schreiben StreamWriter-Objekte Zeichen mit einer speziellen Verschlüsselung (Encoding) in den Datenstrom. Sie arbeiten im Endeffekt mit einem Datenstrom, der die Charakteristika beider Datenflüsse kombiniert. In ähnlicher Weise könnten Sie natürlich auch einen MemoryStream oder NetworkStream als Argument übergeben.

Standardmäßig verschlüsselt StreamWriter nach UTF-8, eine Abweichung davon wird durch die Wahl eines Konstruktors erreicht, der einen Parameter vom Typ Encoding aus dem Namespace System.Text entgegennimmt. Sie können hier beispielsweise ein Objekt vom Typ UTF7Encoding oder UnicodeEncoding (entspricht der UTF-16-Kodierung) übergeben.

Schreiben wir Zeichen in einen Stream, müssen die Bytes in bestimmter Weise interpretierbar sein. Standardmäßig wird in Mitteleuropa zur Kodierung der ANSI-Zeichensatz (Codeseite 1252) benutzt, der Zeichencodes zwischen 0 und 255 zulässt und unter anderem auch Sonderzeichen wie »ä«, »ö« und »ü« beschreibt. Damit unterscheidet sich der ANSI-Zeichensatz vom ASCII-Zeichensatz, der nur die Codes von 0 bis 127 festlegt. Um einen Text korrekt zu übertragen und anzuzeigen, dürfte streng genommen nur der ASCII-Zeichensatz verwendet werden, weil nur die Codes 0–127 unter ANSI und ASCII identisch sind.

Um Probleme dieser Art zu vermeiden, wurde mit Unicode ein neuer Zeichensatz geschaffen. Allerdings hat auch Unicode unterschiedliche Formate, denn es wird zwischen UTF-7, UTF-8, UTF-16 und UTF-32 unterschieden. Der UTF-8-Zeichensatz ist wohl der wichtigste, denn er ist der Standard unter .NET. In diesem Zeichensatz werden Unicode-Zeichen in einer unterschiedlichen Anzahl Bytes verschlüsselt. Die ASCII-Zeichen werden in einem Byte gespeichert, alle anderen Zeichen in weiteren zwei bis vier Byte. Das hat den Vorteil, dass Systeme, die nur ASCII- oder ANSI-Zeichen verarbeiten, mit der UTF-8-Kodierung klarkommen.

Einige Konstruktoren erwarten zusätzlich einen booleschen Wert. Dieser kommt nur im Zusammenhang mit den Konstruktoren vor, die in einer Zeichenfolge die Pfadangabe zu der Datei erhalten, in die der Datenstrom geschrieben werden soll. Mit true werden die zu schreibenden Daten an das Ende der Datei gehängt – vorausgesetzt, es existiert bereits eine Datei gleichen Namens in dem Verzeichnis. Mit der Übergabe von false wird eine existierende Datei überschrieben.

Der letzte Parameter, der Ihnen in zwei Konstruktoren zur Verfügung steht, empfängt einen Wert vom Typ int, mit dem Sie die Größe des Puffers beeinflussen können.

Das Schreiben in den Datenstrom

Schauen wir uns zunächst ein Codefragment an, mit dem wir eine Datei erzeugen, in die wir den obligatorischen Text »Visual C# macht Spaß« schreiben:

StreamWriter sw = new StreamWriter(@"D:\NewFile.txt");
sw.WriteLine("Visual C#");
sw.WriteLine("macht Spaß!");
sw.Close();

Listing 12.8 Mit »StreamWriter« in eine Textdatei schreiben

Einfacher geht es nicht mehr! Zunächst wird ein Konstruktor aufgerufen und diesem zur Initialisierung des StreamWriter-Objekts eine Zeichenkette als Pfadangabe übergeben. Daraufhin wird entweder die Datei erzeugt oder eine existierende gleichnamige Datei im angegebenen Verzeichnis überschrieben. Mit jedem Aufruf der von TextWriter geerbten Methode WriteLine wird eine Zeile in die Datei geschrieben und ihr am Ende ein Zeilenumbruch angehängt. Mit unserem Codefragment erzeugen wir also eine zweizeilige Textdatei.

Es liegt die Vermutung nahe, dass StreamWriter eine zweite Methode zum Schreiben in den Datenstrom bereitstellt, die ohne den automatisch angehängten Zeilenumbruch in den Strom schreibt. Ein Blick in die Klassenbibliothek bestätigt die Vermutung: Es gibt eine Methode Write. Diese Methode ist genauso überladen wie die Methode WriteLine. Write und WriteLine bilden den Kern der Klasse StreamWriter. Viel mehr Methoden hat die Klasse auch nicht anzubieten, denn alle anderen sind bereits gute Bekannte: Close, um einen auf dieser Klasse basierenden Strom zu schließen, und Flush, um die im Puffer befindlichen Daten in den Strom zu schreiben und den Puffer zu leeren. Tabelle 12.16 gibt die wichtigsten Methoden eines StreamWriter-Objekts wieder.

Tabelle 12.16 Methoden eines »StreamWriter«-Objekts

Methode Beschreibung

Close

Schließt das aktuelle Objekt sowie alle eingebetteten Streams.

Flush

Schreibt die gepufferten Daten in den Stream und löscht danach den Inhalt des Puffers.

Write

Schreibt in den Stream, ohne einen Zeilenumbruch anzuhängen.

WriteLine

Schreibt in den Stream und schließt mit einem Zeilenumbruch ab.

Die Eigenschaften der Klasse »StreamWriter«

Mit AutoFlush veranlassen Sie, dass Daten aus dem Puffer in den Datenstrom geschrieben werden, sobald eine der Write/WriteLine-Methoden aufgerufen wird und diese Eigenschaft auf true gesetzt ist. Wollen Sie das aktuelle Textformat erfahren, können Sie die Eigenschaft Encoding auswerten:

StreamWriter sw = new StreamWriter(@"C:\NewFile.txt", false, Encoding.Unicode);
Console.WriteLine("Format: {0}", sw.Encoding.ToString());

Als dritte und letzte Eigenschaft steht Ihnen noch BaseStream zur Verfügung, die das Objekt des Base-Streams liefert, auf dem das StreamWriter-Objekt basiert.

Tabelle 12.17 Die Eigenschaften der Klasse »StreamWriter«

Eigenschaften Beschreibung

AutoFlush

Löscht den Puffer nach jedem Aufruf von Write oder WriteLine.

BaseStream

Liefert eine Referenz auf den Base-Stream zurück.

Encoding

Liefert das aktuelle Encoding-Schema zurück.


Rheinwerk Computing - Zum Seitenanfang

12.5.2 Die Klasse »StreamReader«Zur vorigen Überschrift

Die aus der Klasse TextReader abgeleitete Klasse StreamReader ist das Gegenstück zur Klasse StreamWriter. Betrachtet man ihre Möglichkeiten, sind die Klassen praktisch identisch – abgesehen von der Tatsache, dass das charakteristische Merkmal dieser Klasse in der Fähigkeit zu finden ist, Daten einer bestimmten Kodierung aus einem Strom zu lesen.

Die Konstruktoren ähneln denen der Klasse StreamWriter. Sie nehmen im einfachsten Fall die Referenz auf einen Stream oder eine Pfadangabe als String entgegen. Sie gestatten aber auch, die eingelesenen Zeichen nach einem durch Encoding beschriebenen Schema zu interpretieren oder die Puffergröße zu variieren. Tabelle 12.18 enthält die wichtigsten Methoden eines StreamReaders.

Tabelle 12.18 Methoden der Klasse »StreamReader«

Methode Beschreibung

Peek

Liest ein Zeichen aus dem Strom und liefert den int-Wert zurück, der das Zeichen repräsentiert, verarbeitet das Zeichen aber nicht. Der Zeiger wird nicht auf die Position des folgenden Zeichens gesetzt, wenn Peek aufgerufen wird, sondern verbleibt in seiner Stellung. Verweist der Zeiger hinter den Datenstrom, ist der Rückgabewert –1.

Read

Liest ein oder mehrere Zeichen aus dem Strom und liefert den int-Wert zurück, der das Zeichen repräsentiert. Ist kein Zeichen mehr verfügbar, ist der Rückgabewert –1. Der Positionszeiger verweist auf das nächste zu lesende Zeichen. Eine zweite Variante dieser überladenen Methode liefert die Anzahl der eingelesenen Zeichen.

ReadLine

Liest eine Zeile aus dem Datenstrom – entweder bis zum Zeilenumbruch oder bis zum Ende des Stroms. Der Rückgabewert ist vom Typ string.

ReadToEnd

Liest von der aktuellen Position des Positionszeigers bis zum Ende des Stroms alle Zeichen ein.

Wir wollen nun an einem Codebeispiel das Lesen aus einem Strom testen.

// Beispiel: ..\Kapitel 12\StreamReaderSample
class Program {
static void Main(string[] args) {
// Datei erzeugen und mit Text füllen
StreamWriter sw = new StreamWriter(@"D:\MyTest.kkl");
sw.WriteLine("Visual C#");
sw.WriteLine("macht viel Spass.");
sw.Write("Richtig??");
sw.Close();
// die Datei an der Konsole einlesen
StreamReader sr = new StreamReader(@"D:\MyTest.kkl");
while(sr.Peek() != -1)
Console.WriteLine(sr.ReadLine());
sr.Close();
Console.ReadLine();
}
}

Listing 12.9 Textdatei mit »StreamReader« lesen

Zunächst wird mit einem StreamWriter-Objekt eine Datei mit dem Namen MyTest.kkl erzeugt. Die Dateierweiterung ist frei gewählt, sie muss nicht zwangsläufig .txt zur Kennzeichnung als Textdatei lauten. Wichtig ist nur, die Daten der Datei beim späteren Lesevorgang richtig zu interpretieren. Solange wir wissen, dass wir es mit einer Textdatei zu tun haben, bereitet uns eine individuelle Dateierweiterung keine Probleme.

In den Datenstrom sw vom Typ StreamWriter werden drei Textzeilen geschrieben. Danach darf man nicht vergessen, den Strom wieder zu schließen, denn ansonsten wird man mit einer Fehlermeldung konfrontiert, wenn nachfolgend der Versuch unternommen wird, die Datei zum Lesen zu öffnen.

Um den Dateiinhalt zu lesen, nutzen wir ein Objekt vom Typ StreamReader, dessen Konstruktor wir den Pfad zu der Datei übergeben. Mit der ReadLine-Methode wird Zeile für Zeile aus dem Strom gelesen. Um den Lesevorgang zum richtigen Zeitpunkt wieder zu beenden, müssen wir das Ende der Datei feststellen. Hierbei ist die Methode Peek behilflich, deren Rückgabewert –1 ist, wenn der Zeiger auf die Position hinter dem Ende des Stroms verweist. Dieses Verhalten machen wir uns zunutze, indem wir daraus die Abbruchbedingung der Schleife formulieren. In der while-Schleife werden so lange mit der ReadLine-Methode des StreamReader-Objekts Zeilen aus dem Datenstrom geholt (und dabei wird automatisch der Zeiger auf das nächste einzulesende Zeichen gesetzt), bis die Abbruchbedingung erfüllt wird, d. h. Peek –1 zurückliefert.

Die Ausgabe an der Konsole wird wie folgt lauten:

Visual C#
macht Spass.
Richtig??

Da wir die komplette Textdatei auslesen wollen, könnten wir auch einen einfacheren Weg gehen und die komplette while-Schleife gegen die folgende Programmcodezeile austauschen:

Console.WriteLine(sr.ReadToEnd());


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern