C#: CSV-Datei mit LINQ einlesen

LINQ (Language Integrated Query) bietet eine standardisierte Möglichkeit, nicht nur Tabellen in einer relationalen Datenbank, sondern auch Textdateien, XML-Dateien und andere Datenquellen in einer SQL-ähnlichen Syntax abzufragen. LINQ vereinfacht diese Situation durch die Bereitstellung eines konsistenten Modells zum Arbeiten mit Daten und dabei werden immer dieselben grundlegenden Codierungsmuster für die Abfrage verwendet. Von LINQ existieren nun mehrere Ausprägungen in Form von verschiedenen Providern, z.B. LINQ to Objects (arbeitet mit Collection die IEnumerable implementieren), LINQ to XML (Zugriff auf XML-Strukturen), usw. Ich möchte in diesem Artikel jetzt nicht auf Details zu LINQ bzw. auf die einzelnen Provider eingehen, sondern auf Basis eines kleinen Beispiels zeigen wie einfach es mit LINQ ist eine CSV-Datei einzulesen. Gerade CSV-Dateien werden oft für den Datenaustausch verwendet und können mit LINQ auf einfache Art und Weise verarbeitet werden.

Das Dateiformat CSV steht für englisch Comma-separated values und beschreibt den Aufbau einer Textdatei zur Speicherung oder zum Austausch einfach strukturierter Daten (die Dateinamenserweiterung lautet .csv). Innerhalb der Textdatei haben einige Zeichen eine Sonderfunktion zur Strukturierung der Daten. Ein Zeichen wird zur Trennung von Datensätzen benutzt (normalerweise der Zeilenumbruch) und ein Zeichen wird zur Trennung von Datenfeldern (Spalten) innerhalb der Datensätze benutzt. Allgemein wird dafür das Komma eingesetzt, es sind aber auch Semikolon, Doppelpunkt, Tabulator, Leerzeichen oder andere Zeichen üblich.

Beispiel

Für das Beispiel wird eine CSV-Datei mit den deutschen Postleitzahlen verwendet. Die Datei stammt aus dem OpenGeoDB-Projekt (http://opengeodb.org). Eine aktuelle Version der Postleitzahlen-Datei kann dort auch heruntergeladen werden. Der Inhalt dieser Datei ist wie folgt aufgebaut:

LinqCsvSample_03

In dieser Datei wird das Tabulator-Zeichen als Trennzeichen verwendet. Das Beispielprogramm soll diese Datei einlesen und in einer Liste (Grid) ausgeben. Dazu habe ich einfach mal ein kleines WPF-Projekt erstellt und der Einfachheit halber wird die Datei einfach im Konstruktor des Hauptfensters eingelesen. Das sieht dann wie folgt aus:

Das Einlesen der CSV-Datei erfolgt in den Zeilen 16-25 (die einzulesende Datei muss sich im gleichen Verzeichnis wie die ausführbare Datei befinden). Dabei wird im ersten Schritt die ReadAllLines-Mehtode der statischen Klasse File verwendet. Diese Methode gibt ein string[]-Array mit allen Zeilen der Datei zurück. Dieses Array dient dann als Quelle für die eigentliche Abfrage. Bei Abfrageausdrücken ist es gelegentlich nützlich, das Ergebnis eines Unterausdrucks zu speichern, um es in nachfolgenden Klauseln zu verwenden. Dazu wir das let-Schlüsselwort verwendet. Durch die Verwendung dieses Schlüsselworts wird eine neue Bereichsvariable erstellt und mit dem Ergebnis eines Unterausdrucks initialisiert. Im oben gezeigten Beispiel wird nun das Ergebnis der Split-Methode in der neuen Bereichsvariable plzRecord abgelegt. Die Split-Methode wird verwendet, um eine durch Trennzeichen (in diesem Fall TAB => \t) getrennte Zeichenfolge in Teilzeichenfolgen zu unterbrechen. Danach wird mit select new ein neuer anonymer Typ erzeugt. Unter einem anonymen Typ versteht man eine einfache namenlose Klasse, die automatisch vom Compiler erzeugt wird (weitere Informationen Quelle [4]). Für die Initialisierung der Eigenschaften werden die einzelnen Datenfelder aus der jeweiligen Zeile verwendet.

Hinweis

Für den Zugriff auf die Array-Elemente wird der neue Null Conditional Operator (?.) eingesetzt, der in C# 6.0 eingeführt. Wobei die Syntax ?[] der ?. Syntax entspricht, und zwar immer dann, wenn auf einen Indexer zugegriffen wird (z.B. ein Array oder eine Klasse, die einen Indexer implementiert). Weitere Details zu diesem neuen Operator sind in folgendem Artikel zu finden: C# 6.0: Null-conditional Operator (?.)

Die Ausgabe des Programms sieht dann wie folgt aus:

LinqCsvSample_01

Im Debugger:

LinqCsvSample_02

Das Ergebnis könnte jetzt auch direkt weiter verarbeitet werden, z.B. könnte man die folgende Abfrage ausführen:

In diesem Beispiel wird nun der Ort mit der Postleitzahl „66914“ selektiert. Hier wird die Extension Method-Syntax verwendet. Im Gegensatz dazu wird für das Einlesen der CSV-Datei die Query Expression-Syntax (Abfrage-Syntax) verwendet.

Mit der Hilfe von LINQ ist es also möglich eine CSV-Datei innerhalb eines Statements zu importieren/einzulesen (es werden keine Schleifen usw. benötigt). Weitere Information zu LINQ sind in folgenden Online-Quellen zu finden.

Literaturverzeichnis und Weblinks

Abk.Quelle
[1]OpenGeoDB
http://opengeodb.org
[2]Introduction to LINQ Queries
https://msdn.microsoft.com/de-de/library/bb397906.aspx
[3]101 LINQ Samples
https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
[4]Anonyme Typen
https://msdn.microsoft.com/de-de/library/bb397696.aspx

Quellcode

[wpdm_package id=’1809′]

Fork me on GitHub