C# Txt-Datei einlesen und bearbeiten / umsortieren

thron

Cadet 3rd Year
Registriert
März 2017
Beiträge
60
Hallo an Alle,

bin grad dabei mich mit C# zu beschäftigen und wollte das erlehrnte gerne an eine kleinem Projekt umsetzten umso weiter zu lernen und am Projekt zu basteln. Es geht dabei um GPS-Daten bzw. um Zeilen in einer TXT-Datei.

Ich hab eine Txt-Datei die als *.csv Datei generiert wird, wenn ich diese mit dem Editor öffnen dann habe ich folgende Struktur.

Datum;Zeit;Stadt;Straße;Längengrad;Breitengrad;Geschwindigkeit;
31.03.2017;10:34:05;12345 Musterstadt;Teststraße 3;9,49769;52,99597;15 km/h;
31.03.2017;10:34:05;12345 Musterstadt;Teststraße 5;9,49769;52,99597;15 km/h;
usw..
uws..

Jetzt möchte ich diese Datei gerne einlesen und wein wenig umschreiben / umsortieren.

Und zwar soll diese folgendermaßen aussehen:

Datum;Zeit;Zeitzone;Länge;Breite;Geschwindigkeit;Kurs;Adresse;Aufenthaltszeit;
31.03.2017;10:34:05;UTC+02:00;9,49769;52,99597;15;(Platzhalter);12345 Musterstadt Teststraße 3;
31.03.2017;10:34:05;UTC+02:00;9,49769;52,99597;15;(Platzhalter);12345 Musterstadt Teststraße 3;

Wie kann ich denn eine Datei einlesen um sie dann umsortiert mit neuen Feldern in eine neue Datei hineinzuschreiben. Ist evtl. am Anfang jetzt ein bissl viel aber ich denke das ich an einem kleine Projekt am besten dazulernen kann um mich so zu steigern.

Viele Dank für Eure Hilfe jetzt schon...

Viele Grüße
 
Als erstes würde ich überlegen, ob du das zum Üben alles selber per Hand machen möchtest (Datei einlesen und schreiben), oder dir per NuGet eine CSV-Bibliothek in dein Projekt reinziehst, die das Einlesen und Schreiben der CSV für dich übernimmt.

Ich habe neulich erst CsvHelper für eins meiner Projekte benutzt: https://www.nuget.org/packages/CsvHelper
 
Als Übung kanns nix schaden, Text einlesen und splitten (wenns CSV-Format immer gleich ist) ist jetzt nicht so aufwendig.
Oder am besten gleich in DataTable einfügen, beabreiten und dann Zeile für Zeile, Spalte für Spalte in ner Schleife exportieren. Quotierungen und Zahlenformate noch kontrollieren beim Export. Gibts schon genug Beispiele google mal nach C# DataTable to CSV.
 
Zur Übung würde ich

  • die Datei zeilenweise einlesen (dafür gibt es eine Runtime-Funktion)
  • die so erhaltenen Strings in einer Schleife durchlaufen
  • jeden String zerlegen (auch hierfür gibt es bereits eine entsprechende Funktion) und damit ein neues Objekt erstellen (Waypoint oder Datapoint könnte man dies nennen) und dieses einer Liste hinzufügen
  • die Ausgabedatei öffnen
  • den gewünschten csv-Header ausgeben
  • die neue Liste durchgehen und die Felder in der gewünschten Reihenfolge ausgeben

Man könnte das Lesen und Schreiben auch gleichzeitig durchführen, aber für den Anfang ist eine Trennung übersichtlicher.
 
Was spricht gegen Regex? Es würde sich zumindest für das Auslesen super anbieten und das Formatieren in das eigene Format wäre somit entsprechend leichter.
 
In 99% aller Fälle die Performance in C# ;)
Wenn seine CSV immer gleich formattiert sind (ansonsten macht ja auch ein precompiled Regex keinen Sinn) und keine Zeilenumbrüche haben ist das einfachste das Ergebnis von .Split() einfach per .AddDataRow hinzuzufügen statt sich selbst von Feld zu Feld durch die Matches zu wühlen.
Regex nehm ich echt nur für Komplizierteres, das ist deutlich langsamer als die String-Funktionen (und selbst die sind langsamer als selbst binär zu verarbeiten), allerdings muss ich wöchentlich auch mehrere Millionen Datensätze einlesen und weiterverarbeiten, der TE wird vermutlich nicht ganz soviele Sätze haben ;)
Wahrscheinlich würde für den TE sogar ein Excel-Makro reichen, so klar definiert war ja was er genau macht nicht mengenmässig.
Ansonsten bei kleineren Dateien alles in einen String einlesen und dann
Zeilen= strDaten.Split(Environment.Newline)
Pro Zeile dtMeineDaten.DataRow.Add(Zeilen[x].Split(";"))
Danach die Datatable den wünschen entpsrechend filtern, sortieren etc. und dann schreiben. Vorher das Numberformat der Anwendung passend zur Datei einstellen damit die Zahlen alle automatisch richtig erkannt werden und man nicht pro Zahl casten muss.
 
Zuletzt bearbeitet:
Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();

            foreach (string line in File.ReadAllLines(@"c:\temp\file.txt", Encoding.UTF8))
            {
                string[] values = line.Split(';');
                if (values.Length == 0) continue; //leere Zeile, überspringen

                if (values.Length != 3) throw new Exception("CSV enthält nicht die erwartete Anzahl Spalten");

                string[] newLines = new string[4];

                newLines[0] = values[0];
                newLines[1] = values[2];           
                newLines[2] = "neue Spalte";
                newLines[3] = values[1];

                sb.AppendLine(String.Join(";", newLines));

            }

            File.WriteAllText(@"c:\temp\file2.txt", sb.ToString());
        }
    }
}



So als Einstieg, hoffe du findest es nützlich. Fehlerbehandlung muss natürlich noch verbessert werden:)
Man könnte auch noch den Speicherbedarf optimieren. Wenn man z.B. die Zeilen einzeln ausliest und schreibt,
anstatt auf einmal. Aber das überlass ich dir^^
 
Zuletzt bearbeitet:
hallo...

danke für die zahlreichen Informationen. Habe mich ein wenig eingelesen und zahlreiche Tutorials gelesen. Mein Problem liegt darin, dass ich zwar Daten einlesen kann und sie auch wieder ausgeben kann, aber eben nicht sortieren. Der Schnipsel von unmask007 ist ein guter Einstieg. Aber ich bekomme es irgendwie nicht hin, dass ich ganze "Spalten" verschoben bekomme.

ich bekomme es gedanklich nicht hin, wie ich die Daten nach dem Trennen (;) abspeichern soll und wieder in der richtigen Reihenfolge zusammensetzte. Es handel sich ja nicht um Spalten wie bei Excel sondern um Zahlen und Buchstaben die lediglich durch ein Semikolon getrennt wurden.
 
Du musst den Teil mit NewLines[0]=... schon an Deine gewünsche Reihenfolge anpassen.

Mit einer DataTable wäre das flexibler gewesen, aber ich vermute unmask007 wollte es bewußt einfach halten, daher sind da noch jede Menge Performancebremsen drin und er prüft ob Split leere Zeilen enthält obwohl die zweite Überladung von Split die automatisch entfernen kann ;)
 
ich bekomme es gedanklich nicht hin, wie ich die Daten nach dem Trennen ( abspeichern soll und wieder in der richtigen Reihenfolge zusammensetzte. Es handel sich ja nicht um Spalten wie bei Excel sondern um Zahlen und Buchstaben die lediglich durch ein Semikolon getrennt wurden.

Code:
              string[] newLines = new string[4];  //enthält die Werte der Spalten der neuen Zeile  

                newLines[0] = values[0]; //Wert der Spalte 0 aus der alten Zeile wird in Spalte 0 der neuen Zeile geschrieben
                newLines[1] = values[2]; //Wert der Spalte 2 aus der alten Zeile wird in Spalte 1 der neuen Zeile geschrieben          
                newLines[2] = "neue Spalte"; //Die neue Spalte, die du hinzufügen wolltest (musst du natürlich noch auf deine Problemstellung anpassen)
                newLines[3] = values[1]; //Wert der Spalte 1 aus der alten Zeile wird in Spalte 3 der neuen Zeile geschrieben  

                string newLine = String.Join(";", newLines); //Zusammenfügen der Spalten zu einem Text
                //string newLine = newLines[0]+ ";"+ newLines[1] + ";" + newLines[2] + ";" + newLines[3] //Würde auch gehen, anstatt String.Join
                Console.WriteLine("Alte Zeile: "+ line );
                Console.WriteLine("Neue Zeile: " + newLine);
                Console.ReadKey();
                sb.AppendLine(newLine);

hoffe das ist so verständlicher...
 
hallo....

viele Dank. Habe mir mal einen Stift genommen und die Sache aufgezeichnet jetzt wurde es klarer und es geht voran.
Habe aber noch eine Frage, wie wo muss ich den -1 machen, damit er beim einlesen die Erste Zeile Ignoriert?

in meinem Fall: Datum;Zeit;Stadt;Straße;Längengrad;Breitengrad;Geschwindigkeit;

Viele Dank für die guten Tipps hier....
 
Wieso -1? Einfach die 1. Zeile überspringen. Konkret hängt das davon ab wie du schlussendlich die Daten einliest bzw. darüber iterierst.
 
Tipp: C# kennt nicht nur foreach, sondern auch den althergebrachten for Loop zum Iterieren.
 
Wenn du die Datei einliest, wie in #7, mach dir eine Variable die dir angibt, ob du noch bei der 1. Zeile bist oder nicht.
Oder du erkennst es anhand der Überschriften (interessant auch für die Validierung).
 
Wenn man sich nicht mit den Möglichkeiten der for-Schleife auseinandersetzen möchte, könnte man sich stattdessen näher mit Arrays befassen. Die Array-Klasse in C# bietet eine Methode zum Überspringen.
 
Zurück
Oben