**
**
Vorwort
WICHTIG: Version 2.2: Ich habe die PDF Version in eine BB-Code Version übertragen. Dabei gabs einige kleine Schwierigkeiten, weswegen sich Fehler eingeschlichen haben könnten. Falls ihr welche findet, bitte melden 😉.
In diesem Artikel werde ich versuchen die wichtigsten Möglichkeiten aufzuzeigen, die das .NET Framework zur Dateimanipulation bietet. Dabei werde ich nicht nur bei einfachen Textdateien bleiben, sondern auch XML Dateien behandeln. Ich verwende die Programmiersprache C# für die Codebeispiele in diesem Artikel. Allerdings sollten sie sich ohne Probleme auch mit anderen .NET Programmiersprachen wie z.B. VB .net umsetzen lassen. Ich werde sowohl auf die klassische Art der Dateimanipulation als auch auf die neuen Möglichkeiten des .NET Frameworks 2.0 eingehen.
Um diesen Artikel zu verstehen und ihn nachvollziehen zu können, sollte das Microsoft .NET Framework 1.x oder 2.0 und eine Entwicklungsumgebung installiert sein. Im empfehle Ihnen entweder die kostenlose Entwicklungsumgebung SharpDevelop einzusetzen, oder die Visual Studio Express Editionen von Microsoft. Außerdem sollten Sie bereits ein wenig Erfahrung mit der Entwicklungsumgebung und der .NET Programmiersprache Ihrer Wahl haben. Den Erklärungen folgt immer ein Codebeispiel, dass das beschriebene Thema an Hand eines Praxisbeispiels vertieft. Die Codebeispiele sind mit vielen Kommentaren ausgestattet.
Ich wünsche Ihnen viel Spaß beim Lesen dieses Artikels. Falls Sie Fragen, Wünsche oder Anregungen haben, bitte diese einfach hier posten 😉.
Dateien lesen und schreiben
In diesem Kapitel zeige ich Ihnen die Möglichkeiten, Dateien einzulesen und Dinge in Dateien zu schreiben, die das .NET Framework bietet. Die Codebeispiele sind absichtlich einfach gehalten und verzichten auf eine Fehlerbehandlung, welche im Normalfall unbedingt angewendet werden sollte.
**:::
**:::
**:::
using System;
using System.IO;
using System.Windows.Forms;
namespace SimonKnight6600.Tutorials
{
public class Program
{
static void Main()
{
// Datei erzeugen und öffnen
StreamWriter writer = File.CreateText(Application.StartupPath +
"\\telefonnummern.txt");
// Ein paar Einträge hineinschreiben
writer.WriteLine("Thomas;223245");
writer.WriteLine("Matze;22741");
writer.WriteLine("Michael;357228");
writer.WriteLine("Richard;242531");
writer.WriteLine("Dominik;242352");
writer.Close(); // Den Dateizugriff beenden
}
}
}
**:::
Im wesentlich beziehe ich mich dabei auf die Klasse File, die neue statische Methoden enthält die uns das Schreiben von Dateien erleichtern. Die Methode WriteAllText() schreibt den ihr übergebenen Text in eine Datei. Der Methode WriteAllLines() können Sie ein string Array übergeben, in dem sich die einzelnen Zeilen der Datei befinden.
Das oben gezeige Codebeispiel könnte, mit Hilfe der File Klasse realisiert, auch so aussehen:
using System;
using System.IO;
using System.Windows.Forms;
namespace SimonKnight6600.Tutorials
{
public class Program
{
static void Main()
{
// Die Telefonnummmern-Liste als string[] Array
string[] zeilen = new string[] { "Thomas;223245",
"Matze;22741", "Michael;357228", "Richard;242531", "Dominik;242352" };
// Datei schreiben
File.WriteAllLines(Application.StartupPath +
"\\telefonnummern.txt", zeilen);
}
}
}
**:::
Das folgende Beispiel liest die von den obigen Beispielen erzeuge Datei „telefonnummern.txt“ wieder ein und gibt das Ergebnis formatiert über die Konsole aus.
Das Einlesen funktioniert, wie beim Schreiben, zeilenweise. Statt der Methode WriteLine() rufen wir zum Einlesen die Methode ReadLine() von StreamReader auf.
using System;
using System.IO;
using System.Windows.Forms;
namespace SimonKnight6600.Tutorials
{
public class Program
{
static void Main()
{
// StreamReader Instanz erzeugen und Datei öffnen
StreamReader reader = new StreamReader(Application.StartupPath
+ "\\telefonnummern.txt");
do
{
// Aktuelle Zeile einlesen und aufteilen
string[] zeile = reader.ReadLine().Split(';');
string name = zeile[0];
string telefonnummer = zeile[1];
// Name und Telefonnummer ausgeben
Console.WriteLine("Name: " + name + " Telefonummer: " + telefonnummer);
// Falls Peek -1 zurückgibt, sind wir am Ende der Datei
} while (reader.Peek() != -1);
// Dateizugriff beenden
reader.Close();
Console.ReadLine();
}
}
}
**:::
Die von den Schreibbeispielen erstellte Telefonnummen-Liste könnte auch so eingelesen und ausgegeben werden:
using System;
using System.IO;
using System.Windows.Forms;
namespace SimonKnight6600.Tutorials
{
public class Program
{
static void Main()
{
// Alle Zeilen in einem Rutsch einlesen
string[] zeilen = File.ReadAllLines(Application.StartupPath +
"\\telefonnummern.txt");
// Alle Zeilen in einer Schleife durchlaufen
foreach (string zeile in zeilen)
{
// Zeile aufteilen
string[] aufgeteilt = zeile.Split(';');
// Ausgeben
Console.WriteLine("Name: " + aufgeteilt[0] +
"Telefonnummer: " + aufgeteilt[1]);
}
Console.ReadLine();
}
}
}
XML Dateien
**:::
XML ist sehr weit verbreitet. XHTML, RSS und das Dateiformat des kommenden Microsoft Office 2007 sind nur einige populäre und auf XML basierende Dateiformate. Ein weiterer Vorteil von XML ist seine Platformunabhänigkeit. XML kann von von Programmen jedes Betriebssystems eingelesen werden.
Falls Sie weitergehende Informationen über XML möchten, können Sie den ausgezeichneten Wikipedia-Artikel lesen. Im Folgenden werde ich nur einen groben Überblick über den Aufbau von XML Dateien bieten.
In XML Dateien können Sie z.B. Programmeinstellungen abspeichern. Dies werden wir in einem späteren Beispiel auch machen.
**:::
<Benutzername>Robert</Benutzername>
Der rote Text ist das Start-Tag. Der Text zwischen spitzen Klammern ist der Name des Tags.
Der grüne Text ist das End-Tag. Es ist gleich aufgebaut wie das Start-Tag, der -Zeichen nach der spitzen Klammer. Wichtig ist,
dass der Text zwischen den Spitzen Klammern gleich wie der Name des Tags ist.
Zwischen diesen beiden Teilen ist der Inhalt des Elements, in diesem Fall "Robert".
Beispiel für ein falsches Element:
<Benutzer>Simon</Benutzerrrrr>
Das ist falsch, da im End-Tag der Text (grün markiert) anders als der Text im Start-Tag (rot markiert) ist.
**Richtig wäre zum Beispiel dieses Element, da der Text im Start- und End-Tag gleich ist: **
<Benutzer>Simon</Benutzer>
Oder auch dieses:
<Obst>Apfel</Obst>
**:::
<Benutzerliste>
<Benutzer>Robert</Benutzer>
<Benutzer>Simon</Benutzer>
</Benutzerliste>
Wichtig ist, dass jedes Element einen Anfang und ein Ende hat. Zur besseren übersicht habe ich nochmals die Start-Tags rot und die End-Tags grün eingefärbt.
**:::
So könnte es in dem Beispiel der Benutzerliste unterschiedliche Benutzer
geben: Standard-Benutzer und Premium-Benutzer. Diese Information könnten
Attribute werden nach dem Namen des Start-Tags untergebracht.
Beispiel:
<Benutzer typ="standard">Robert</Benutzer>
Beispiel für einen Premium-Benutzer:
<Benutzer typ="premium">Simon</Benutzer>
Der in den Beispielen rot gefärbte Text ist der Name des Attributs, in unserem Fall „typ“. Der grün gefärbte Text ist der Inhalt des Attributs. In unserer Benutzerliste schreiben wir hier entweder „premium“ oder „standard“.
**:::
<Benutzer name="Robert" typ="standard " />
Da in diesem Fall der Inhalt des Tags leer ist, können wir das End-Tag
weglassen, müssen aber vor der schließenden spitzen Klammer des Start-Tags ein "/"-Zeichen setzen. Beispiel:
<Benutzer name="Robert" typ="standard" />
Das Start-Tag wird in diesem Fall "Empty-Element-Tag" genannt.
In den folgenden Erklärungsbeispielen schreibe ich aber, wie vorher, den
Benutzernamen in den Inhalt des Tags.
**:::
**:::
FALSCH: (Kompletter Dateiinhalt)
<Benutzer>Simon</Benutzer>
<Benutzer>Thomas</Benutzer>
RICHTIG: (Kompletter Dateiinhalt)
<Programmbenutzer>
<Benutzer>Simon</Benutzer>
<Benutzer>Thomas</Benutzer>
</Programmbenutzer>
**:::
<?xml version="1.0" encoding="utf-8" ?>
Wie Sie sicher erkennen, hat diese vom Aufbau her eine große Ähnlichkeit zu XML Elementen. So erkennt man die Attribute „version“ und „encoding“. Mithilfe des Attributs „version“ gibt man die XML-Version an und im Attribut encoding den Zeichensatz. Wenn Sie XML-Dateien mithilfe des .NET Frameworks erzeugen, wird diese XML Deklaration automatisch erzeugt.
**:::
Die folgenden Codebeispiele werden eine einfache Konfigurationsdatei erzeugen und einlesen. Für das Beispiel habe ich folgenden Aufbau gewählt. (Diesen können Sie natürlich an ihre Bedürfnisse anpassen)
<?xml version="1.0" encoding="utf-8" ?>
<Einstellungen>
<SplashAnzeigen>Ja</SplashAnzeigen>
<Autoupdate>Nein</Autoupdate>
<Programmversion>1.0.2</Programmversion>
</Einstellungen>
Was in den Tags gespeichert werden soll, sollte selbsterklärend sein.
**:::
Zum Schreiben von XML Dateien verwenden wir die Klasse XmlWriter. Diese verwendet man, indem man die Methode Create() der Klasse aufruft, also:
XmlWriter writer = XmlWriter.Create(Application.StartupPath + "\\configuration.xml");
Der XmlWriter funktioniert folgendermaßen: Es wird immer zuerst eine Methode WriteStart..... aufgerufen, dann damit gearbeitet und dann die Methode WriteEnd..... aufgerufen.
Konkret heißt das, dass wir zum Beispiel WriteStartElement() aufrufen, um ein Element zu erzeugen, dann den Inhalt des Elements mit WriteString() hineinschreiben oder Attribute mit WriteAttributeString() erzeugen und danach die Methode WriteEndElement() aufrufen.
Bevor wir Elemente in die Xml-Datei schreiben können, müssen wir die Methode WriteStartDocument() aufrufen. Die schreibt die im vorherigen Abschnitt XmlDeklaration beschriebenen Informationen in das Dokument.
Nach der Arbeit müssen wir natürlich wieder WriteEndDocument() aufrufen. Sie sehen, die Arbeit verläuft immer nach dem gleichen Schema.
Das Ganze klingt jetzt vieleicht etwas kompliziert, aber das folgende Codebeispiel sollte für etwas mehr Klarheit sorgen. Es erzeugt die beschriebene XML-Datei mit dem Namen "configuration.xml" im Verzeichnis der Anwendung.
using System;
using System.IO;
using System.Windows.Forms;
using System.Xml;
namespace SimonKnight6600.Tutorials
{
public class Program
{
static void Main()
{
// XmlWriter-Instanz erzeugen
XmlWriter writer = XmlWriter.Create(Application.StartupPath + "\\configuration.xml");
// Mit dem Schreiben des Dokuments beginnen
writer.WriteStartDocument();
// Wurzelelement 'Einstellungen' erzeugen und in
// diesem weiterarbeiten
writer.WriteStartElement("Einstellungen");
// Element 'SplashAnzeigen' erzeugen und in diesem
// weiterarbeiten
writer.WriteStartElement("SplashAnzeigen");
// Inhalt in das Element schreiben
writer.WriteString("Ja");
// Die Arbeit mit dem Elemenet beenden (Ende-Tag
// wird erzeugt)
writer.WriteEndElement();
// Nun machen wir das Gleiche wie in dem vorherigen
// Code, nur mit dem Element 'Autoupdate'
writer.WriteStartElement("Autoupdate");
writer.WriteString("Nein");
writer.WriteEndElement();
// Und nocheinmal. Diesmal mit dem Element
// 'Programmversion'
writer.WriteStartElement("Programmversion");
writer.WriteString("1.0.2");
writer.WriteEndElement();
// Nun müssen wir das das am Anfang erzeuge
// Element 'Einstellungen' schließen...
writer.WriteEndElement();
// ... und die Arbeit mit dem Dokument beenden
writer.WriteEndDocument();
// Den XmlWriter schließen
writer.Close();
}
}
}
Wie Sie sehen, wird zuerst eine Instanz von XmlWriter erzeugt. Nach wird die Methode WriteStartDocument() aufgerufen, um mit der Arbeit zu beginnen. Nun wird das Wurzelelement erzeugt, dass in unserem Fall „Einstellungen“ heißt.
Jetzt durchlaufen wir für jedes Element die Prozedur von WriteStartElement(), WriteString() und WriteEndElement().
Schließlich wird das am Anfang erzeugte Wurzelelement genauso wie andere Elemente geschlossen und die Arbeit mithilfe von WriteEndDocument() abgeschlossen.
Abschließend wird der Zugriff auf die Datei mittels Aufruf der Close() Methode geschlossen.
**:::
Wir können sofort loslegen ohne vorher eine Methode aufzurufen, um die Arbeit zu beginnen.
Zuerst öffnen wir das Wurzel-Element. Nun durchlaufen wir für jeden Element die Prozedur von ReadStartElement(), ReadString() und ReadEndElement(). Das Ergebnis von ReadString() geben wir gleich über Console.WriteLine() aus, damit wir auch sehen, dass es funktioniert.
Abschließend wird das Wurzel-Element geschlossen und der Dateizugriff beendet.
Damit wir die Ausgaben auf der Konsole auch sehen können, rufen wir die Methode Console.ReadLine() auf.
Damit das Beispiel funktioniert, muss natürlich die Datei "configuration.xml" vorhanden sein.
using System;
using System.IO;
using System.Windows.Forms;
using System.Xml;
namespace SimonKnight6600.Tutorials
{
public class Program
{
static void Main()
{
// Instanz von XmlReader erzeugen
XmlReader reader =
XmlReader.Create(Application.StartupPath + "\\configuration.xml");
// Das Wurzelelement 'Einstellungen' öffnen
reader.ReadStartElement("Einstellungen");
// Element 'SplashAnzeigen' öffnen
reader.ReadStartElement("SplashAnzeigen");
// Inhalt per reader.ReadString() auslesen und per
// Console.WriteLine() gleich ausgeben
Console.WriteLine("SplashAnzeigen:
"+reader.ReadString());
// Element 'SplashAnzeigen' schließen
reader.ReadEndElement();
// Die gleiche Prozedur wie vorher, diesmal
// mit dem Element 'Autoupdate'
reader.ReadStartElement("Autoupdate");
Console.WriteLine("Autoupdate: " + reader.ReadString());
reader.ReadEndElement();
// Und nocheinmal. Nun mit dem Element
// 'Programmversion'
reader.ReadStartElement("Programmversion");
Console.WriteLine("Programmversion: " +
reader.ReadString());
reader.ReadEndElement();
// Das am Anfang geöffnete Wurzelelement schließen
// und den Dateizugriff beenden
reader.ReadEndElement();
reader.Close();
// Die Konsole so lange offen halten, bis man die
// ENTER Taste drückt, sonst würde man die
// Ausgaben nicht sehen
Console.ReadLine();
}
}
}
Anhänge
**:::
Wie bereits gesagt, sehr gutes Tutorial! Vielen Dank, mach weiter so! 👍 🙂
Ich habe soeben eine neue Version veröffentlicht. Diese enthält enthält einige Korrekturen von Rechtschreib- und Tippfehlern.
Hallo SimonKnight6600,
vielen Dank für deine super Tutorial 👍
Bin ein kompletter Einsteiger was Programmieren angeht und mir helfen so super geschriebenen Sachen sehr viel weiter!
cozzydog
Ich bin noch ein Anfänger, möchte aber keine fertige Lösung von euch sondern gute Tipps zur Selbsthilfe 😉
Meist ist es für uns Anfänger (bzw mich) einfach nur ein Problem nach dem richtigen zu suchen...
Hallo SimonKnight
Der Downloadlink scheint nicht zu funktionieren....!
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Original von Peter Bucher
Der Downloadlink scheint nicht zu funktionieren....!
Ja, auch bei mir von zu Hause aus (56-k) kann ich ihn nicht öffnen, bzw. ich klicke auf den Link, dann wird die pdf-Datei geladen aber sobald sie geladen ist, wird sie nur für 1/10 Sekunde angezeigt, dann wird der Tab wieder weiß. (Windows XP Home Edition SP2, Firefox 1.5.0.4)
Von einem anderen Ort mit Hochgeschwindigkeitsinternet (100 MBit/s) 🙂 funktioniert es meistens. (Windows 2000 mit SPs, Firefox 1.5.0.5)
Zum Tutorial:
Obwohl ich mich mit dem Umgang von Dateien schon auskenne, habe ich mir den Artikel angesehen. Einige Rechtschreibfehler sind noch vorhanden, ansonsten wirkt das Tutorial sehr professionell. IMHO ist es auch gut verständlich.
Eine Frage habe ich aber:
Funktioniert
(reader.Peek() != -1)
nur mit .NET 2.0? Was für Alternative gibt es für .NET 1.1?
mfg
webstarg
Habe hier 3.5Mbit ADSL...
Not Found
The requested URL /downloads/Alles über Dateien 2.0.pdf was not found on this server.Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Hallo zusammen,
alle die Probleme mit dem Download hatten, finden die Version von heute als Dateianhang oben am Ende des ersten Beitrags.
herbivore
Original von webstarg
Eine Frage habe ich aber:
Funktioniert(reader.Peek() != -1)
nur mit .NET 2.0?
Funktioniert trotzdem.
Mein Fehler.
Alles klar.
webstarg
Hallo!
Entschuldigt, dass ich den Link nicht korrigiert habe, ich war 14 Tage auf Urlaub. Ich hab den Link jetzt korrigiert und den Anhang entfernt.
@herbivore: Vielen Dank für dein Engagement 🙂
Gruß,
SimonKnight6600
Hallo,
wenn ich etwas Feedback geben dürfte: Ein klasse Tutorial das viel einfach erklärt und mir sehr geholfen hat, nur stört mich die Formatierung etwas:
Codeschnipsel sollten Monospace formatiert sein, um die Übersicht wahren zu können - es sieht einfach besser aus wenn man Monospace verwendet.
Das ist im ersten Teil leider nicht der Fall. Wenn man das ändern könnte 🙂
Hoffe das ist nicht zu viel verlangt 😉
Grüße
chaosgeist
Hi, das Tut ist für den ersten Einsatz mit Dateien klasse.
Mir persöhnlich fehlt bei dem Titel alles über Dateien aber folgendes ...
Wie finde ich den aktuellen Datei-Status heraus? (z.B. Datei ist geöffnet, schreibgeschützt etc.)
Wie verändere ich den Status? (Schreibgeschützt in nicht geschützt)
Aber sonst klasse!
Gruß, maYer
Hallo zusammen!
Ich habe nun Version 2.0.2 veröffentlicht. Download und Changelog siehe erster Beitrag.
@chaosgeist: Vielen Dank für den Tipp! In der neuen Version sind jetzt alle Codebeispiele in einer Monospace Schriftart formatiert.
@Wolf_maYer: Ebenfalls vielen Dank für das Feedback! Ich werd mich der Sache annehmen und deine Wünsche in die nächste(n) Version(en) einbauen.
Gruß,
SimonKnight6600
Hallo SimonKnight6600,
auch ich finde das Tutorial wirklich gelungen.
Eine Sache vermisse ich aber bei dem Kapitel "Dateien lesen und schreiben", und zwar wie eine Textdatei erweitert werden kann, also die Benutzung der Methode Seek(...). Sicherlich nur eine Kleinigkeit, macht die Sache aber vollständiger, denke ich.
Gruss
Friedel
Ohne Ziel ist auch der Weg egal.
Hallo Friedel!
Original von Friedel
auch ich finde das Tutorial wirklich gelungen.
Vielen Dank!
Original von Friedel
Eine Sache vermisse ich aber bei dem Kapitel "Dateien lesen und schreiben", und zwar wie eine Textdatei erweitert werden kann, also die Benutzung der Methode Seek(...).
Ist nun auf der ToDo-Liste!
Gruß,
SimonKnight6600
Moin
Vielen Dank für das Tutorial,ist echt gelungen!
Natürlich kann man noch Erweiterungen einbauen(zb. nach einem bestimmten Text in der Datei suchen), aber dann würde es sicher zu Umfangreich werden und man könnte gleich nen Buch schréiben.
Also nochmals vielen Dank.
Ich würds mir ja gerne anschauen, aber irgendwie funzt der Link bei mir nicht. Könnte jemand einen funktionieren posten?
Hallo Kamikaze,
hm, weiß nicht, was ihr für Probleme mit dem Link habt. Bei mir hat der immer funktioniert. So auch jetzt wieder.
Aber ich hänge den Stand 2.0.2b mal hier an.
herbivore
Hallo herbivore!
Man bist du schnell 😄. Ich hab den Link korrigiert, die Datei liegt jetzt auf nem anderen Webspace und es sollte jetzt (hoffentlich) keine Probleme mehr geben...
Gruß,
SimonKnight6600
Jup, jetzt funktioniert es auch wieder...Dankeschön.
Der Artikelist recht nett geschrieben. Ich hatte aber gehofft etwas mehr über umlaute zu lesen. Aber vielleicht kannst du auch kurzfristig auf eine Frage antworten. Wie schreibe ich mit sagen wir unicode in eine Datei? Mein problem was, dass ich mit folgendem Code in eine datei geschrieben hatte und es nicht allzu klasse ausschaut wenn ich sie wieder auslese wegen den Umlauten.
mein code sieht ungefähr so aus:
...
FileInfo fi = new Fileinfo(dateiname);
StreamWriter sw = fi.CreateText();
sw.WriteLine("irgendwas mit umlauten");
sw.Flush();
sw.Close();
...
hoffe du kannst mir nen Tipp geben sonst muss ich weiter googlen :p
Limitless pleasures are highly overrated.
Hallo bata,
du musst beim Erzeugen des StreamWriters das passende Encoding angeben. Grundsätzlich ist die Encoding-Klasse hier der Schlüssel.
herbivore
aaaaaaah danke!
hab jetzt
StreamWriter sw = new StreamWriter(targetPath, false, System.Text.Encoding.Unicode);
statt dem Unsinn mit der FileInfo (da konnte ich kein encoding angeben -.-)
hast mir weitergeholfen danke dir 😁
Limitless pleasures are highly overrated.
Bei mir funzt es irgendwie nicht....
Mein Adobe Reader verreckt immer 🙁
mfg. Daniel 😁
Hallo zusammen
Original von SimonKnight6600
Nimm den
> . Der ist performanter und funzt bei mir.
Diesen Reader kann ich auch wärmstens empfehlen, sauschnell und klein.
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Hallo zusammen!
Ich habe jetzt die PDF Version in eine BB-Code Version übertragen. Ich hatte dabei einige kleine Probleme. Falls irgendwelche Sätze abgeschnitten sind oder sich sonstige Fehler eingeschlichen haben, bitte diese hier posten 🙂.
vg,
Simon
Hi,
gibt es die Version 2.2 irgendwo zum download? Ausdrucken ist sonst ein wenig umständlich.
Gruß, Hendrik
Hallo Hendrik,
herbivore
PS: Wobei ich quasi nur noch am Bildschirm lese. Ich habe zu oft Sachen ausgedruckt, die ich dann doch nie gelesen habe. Außerdem gehen Such- und Kopiermöglichkeiten durch das Ausdrucken verloren. Und solang ist der Artikel ja nun auch wieder nicht, dass man ihn unbedingt auf Papier bräuchte.
Aber das ist nur eine persönliche Anmerkung. Bitte hier im Artikel-Thread keinen Streit über die Sinnhaftigkeit von Ausdrucken.
echt schön zu lesen und hat mir echt weiter geholfen.
Danke
Ich hab gerade diesen Artikel für mich entdeckt und frag mich gerade, warum ich heute ein paar Stunden damit verbracht habe, genau diese infos im netz zusammen zu suchen...
echt super geschrieben