Was ist CSV, wo findet man sowas?
CSV ist ein textbasiertes Dateiformat, in dem Daten getrennt durch ein Trennzeichen abgelegt werden. Das ist der groesste gemeinsame Nenner, auf den sich alle Definitionen von CSV zusammenfassen lassen. Mehr Gemeinsamkeit ist nicht drin, denn ab dort beginnt jeder Nutzer von CSV ein wenig, sein eigeges Sueppchen zu kochen. Die einen benutzen ein Semikolon als Trenner, die anderen ein Komma. Die naechsten benutzen einen Tab und dritte gleich irgendeinen Whitespace.
Warum benutzt man sowas?
Es gibt diverse Systeme, die sich damit befassen, Daten zu sammeln. Und viele Anwendungen dafuer. Manchmal aber will man zur Eingabe kein komplettes Tabellenkalkulationssystem eines grossen Herstellers (und auch keine variante mit vielen Os) verwenden, weil diese einfach das Zielsystem ueberlasten und -laden wuerden. Stattdessen wird, da es alleinig um eine Erfassung geht, ein kleines und schlankes System gewuenscht. Um die Daten anschliessend dann doch in genannten Systemen verwenden zu koennen ist CSV ein nicht unangenehmes Format. Zumal es ausser den Nutzdaten keinerlei Metadaten enthaelt. Das kann man als Schwaeche sehen, ich sehe es als Staerke bezueglich der Kontrolle ueber die Daten.
Warum meine Implementation sich nicht verstecken muss
Meine Implementation mag klein sein, sie mag noch ihre Fehler haben -- aber damit bin ich nicht allein, und das fuehlt sich so gut an. Denn auch grosse und weiche Softwareriesen schaffen manchmal nicht das Quaentchen Konsistenz, welches dazu fuehrt, dass eine selbsterstellte Datei auch selbst wieder gelesen werden kann. Ok, Konkret: Gegeben ein Microsoft Office 2000 mit Microsoft Excel. Gegeben ein paar Datensaetze in einer Tabelle. Nun moege man diese als CSV-Datei exportieren. Dabei wird mit Semikola getrennt. Dann moege man versuchen, diese Datei mit Excel zu oeffen (z.B. mittels Doppelklick oder Enter, den Excel sieht sich als Standardhandler). Und nun werden die Zellen nicht wieder erkannt. Denn Excel trennt beim Einlesen durch Komma. Tja, schade, offenbar nie getestet.. sechs, setzen. Oder? Naja, eine gruendliche Recherche spaeter tat sich auf, dass Excel wohl mal ordentlich implementiert war. So, im Prinzip, was CSV angeht. Aber dann kam die Uebersetzung fuer den deutschen Sprachraum.
Und dabei wurde folgendes getan: In den USA werden Nachkommastellen durch Punkte abgetrennt. Also ist ein Semikolon eine sinnvolle Wahl, weil dann das Trennzeichen moeglichst selten in den Eingabedaten auftritt. Im deutschsprachigen Raum hingegen hat sich das Komma als Trennzeichen durchgesetzt und das Semikolon ist ein brauchbarer Ersatz. Das wurde beim Speichern beruecksichtigt, aber diejenigen, die das Laden bearbeitet haben, ahnten nichts davon. Tja, und schon presst man es auf CDs und verkauft sowas. Meine Klassen beherrschen das Speichern und Laden mit (dem gleichen) frei waehlbaren Trennzeichen zu meiner vollen Zufriedenheit.
Warum sollte man heute noch CSV aktiv und nicht nur als Austauschformat nutzen?
Interoperabilitaet. Datensicherheit. Buzzwords!
Wenn die Daten ausreichend einfach in einer einzelnen Tabelle zusammenzufassen sind und zudem noch mit einem nicht allzuhohen Datenaufkommen zu rechnen ist, dann ist CSV in Betracht zu ziehen, da es gegenueber zum Beispiel einem Datenbanksystem ein paar (wie ich finde bestechende) Vorteile bietet:
- Austauschbarkeit. Eine CSV-Datei ist unter Microsoft Windows genauso eine zeilenbasierte kommagetrennte Datei wie unter einem Unix. Es sind keine Problematiken mit Endianess oder anderen Dingen zu befuerchten, die den Austausch von binaeren Dateien aus Entwicklersicht verkomplizieren. Das Schlimmste, was passieren kann, ist dass von CRLF nach CR zu wandeln ist - also ausreichend trivial.
- Menschenlesbarkeit. Eine CSV-Datei mag dem nicht mit den Daten vertrauten wie ein endloses Gewirr aus Zeichenketten vorkommen, ist aber nach Begreifen des Zeilenaufbaus mit einem einfachen Editor zu bearbeiten oder auch nur zu Durchsuchen.
- Skripteignung. Eine CSV-Datei kann ohne allzu viele Umstaende mit einem Shell-Skript auseinandergepflueckt und verarbeitet werden, hier seien awk und sed als Werkzeuge genannt. Man kann damit tolle Dinge machen. Vom Erstellen von Webseiten bis hin zur Serienbriefverarbeitung mit Makefiles ist alles moeglich (letzteres habe ich auch getan und es ist toll. Vielleicht schreibe ich ja mal drueber...).
- Datensicherheit. Eine CSV-Datei ist eine Textdatei. Eine Datei. Von der der Nutzer genau weiss, wo sie liegt. Die er sichern kann. Die aufgrund ihrer Beschaffenheit (Text) nicht nach einem Versionsupdate des verarbeitenden Systems unbrauchbar werden kann und nur durch ein Downgrade auszulesen ist.
- Redundanz. Was an Daten in einen Datensatz gehoert muss in eine Zeile, da eine CSV-Datei prinzipiell nur genau eine Tabelle beinhaltet. Das bringt grosse Redundanzen mit sich.
- Keine Managementtools. Datenbanken bringen oft tolle Webfrontends oder Anwendungen mit, welche die Administration der Daten und Tabellen stark vereinfachen. Sowas ist mit CSV nicht drin. Naja, immerhin hab ich nun einen Editor geschrieben :)
- Verstreutheit. Ueberall im Dateisystem liegen irgendwelche moeglicherweise redundanten Daten in einzelnen Dateien umher. Eklig bei einem Backup.
Warum nun einen Treiber fuer Java und nicht fuer eine tollererere Sprache entwickeln?
Die urspruengliche Absicht war es nicht, einen Treiber fuer Java zu schreiben. Die urspruengliche Absicht, war einen Editor fuer CSV-Dateien zu entwickeln. Java kam gelegen, weil es damit auf ausreichend vielen unterschiedlichen Plattformen moeglich ist, ein GUI darzustellen. Und das ohne die Kunstgriffe und Verrenkungen, die C gefordert haette. Und da der Editor die CSV-Dateien sowohl lesen wie auch schreiben koennen musste und die Modularisierung ja modern und in Java ein unantastbares Dogma ist war eine Auslagerung des Schreibens, Parsens und Lesens in eigene Klassen nur konsequente Schritte. So entstand dies hier. Wenn sich viel Zeit zusammenballt, koennten auch noch mal Treiber fuer C entstehen.
Wie funktioniert das Parsen?
Das Kernstueck ist weniger das Schreiben von Daten, als das Einlesen. Ganz am Anfang stand die Suche nach einem Regex, der CSV sauber aufzutrennen in der Lage ist. Der fand sich auf http://weblogs.asp.net/prieck/archive/2004/01/16/59457.aspx und anderen Seiten .. und damit er der Welt nicht verlorengeht, habe ich ihn in meiner Form hier auch nochmal:
String [] sarr = s.split(seperator + "(?=([^\"]*\"[^\"]*\")*(?![^\"]*\"))");Dann ist da ja noch die leidige Sache mit den Trennern im Datenteil, die ja auch mal erwuenscht sein koennen. Fuer meine Dateien habe ich ein an Excel angelehntes Verfahren gewaehlt: Wenn der Trenner vorkommt, wird der komplette Feldinhalt in Anfuehrungszeichen eingeschlossen. Und wenn nun im Datenteil steht, dass der komplette Datenteil in Anfuehrungszeichen steht? Dann werden es eben doppelte. Natuerlich ist es noch immer moeglich, dass man im Datenteil versehentlich (oder auch nicht..) eine Zeichenfolge erwischt, die ein Feldtrenner ist. Das ist moeglich und ohne allzu grossen Aufwand (Escaping als Alternative waere moeglich, wuerde aber den verbliebenen Rest Kompatibilitaet mit Excel, der ja mal im Vordergrund stand hinwegspuelen) moeglich, allerdings unwahrscheinlich, dass es zufaellig passiert, wenn ein Feld nicht zur Speicherung unencodeter Binaerdaten genutzt wird...
Orgware
Nachdem das Kernstueck, das Laden der Daten geschafft war, war der Rest nur noch Organisation rund um das halten und im Speicher anordnen der Daten, also eigentlich unspektakulaeres Spielen mit Listen und Iteratoren. Das Speichern muss nur die beschriebene Verpackung von Trennzeichen beherrschein - ansonsten auch kein grosses Kunststueck.