Ganz grob ist das schon in Ordnung. Nur würde ich beim Einlesen der Datei eher die Strategie verfolgen, die Strings so schnell wie möglich loszuwerden, denn mit Strings kannst du nicht rechnen. Daher würde ich den Record TDatensatz statt mit Strings gleich mit den richtigen Datentypen deklarieren:
Code: Alles auswählen
type
TDatensatz = record
IDNr: Integer;
LfdNr: Integer;
Zahl: Double;
Datum: TDate;
Text: String;
Betrag: Double;
end;
Und dementsprechend würde ich die eingelesenen Daten nicht in einem CSVDocument speichern (denn da sind sie ja Strings), sondern z.B. in einem Array (oder einer Liste, TList, o.ä - aber das führt für den Wiedereinstieg wahrscheinlich zu weit). Für das Einlesen selbst reicht dann der CSVParser (oder man macht alles gleich "händisch" mit einer StringList, so schwer ist das nicht).
Arrays sind in FPC dynamisch, d.h. man kann mit SetLength() ihre Länge zur Laufzeit festlegen. Da die Anzahl der Zeilen nicht bekannt ist, reserviere ich immer in Blöcken von, z.B., 1000 Arrayelementen und lasse einen Zähler mitlaufen. Immer wenn der Zählerstand ohne Rest durch 1000 teilbar ist, ist der Block voll, und es wird die Arraylänge um weitere 1000 Elemente vergrößert. Am Ende des Einlesens wird dann das Array auf die nun bekannte Länge gtrimmt. (Man könnte das Array auch nach jeder Zeile um 1 Element verlängern, aber wenn die Datei groß ist, wird man das permanente umkopieren der Daten in der Geschwindigkeit merken).
Beim Umwandeln der Strings in Zahlen gibt es noch die Unschönheit, dass deine Werte einen Tausendertrenner enthalten, was keine der vorhanden Konvertierungsroutinen mag. Daher habe ich eine Routine ThSepStrToFloat geschrieben, die zuerst das Tausendertrennzeichen aus dem String entfernt und dann die Konvertierung durchführt.
Damit man etwas sieht habe ich zum Schluss das Daten-Array in einem Memo ausgegeben. Dabei kommt die Format()-Routine zum Einsatz, mit der man alle möglichen Datentypen zu einem String zusammen bauen kann. Ist am Anfang sicher umgewohnt, aber später unerlässlich, um ellenlange Stringverkettungsoperationen zu vermeiden. Schau dir die Dokumentation dazu an (
https://www.freepascal.org/docs-html/rt ... ormat.html).
Deine eigenen Routinen zum Auffüllen eines Strings auf eine bestimmte Länge sind unnötig, sie gibt es schon in der Unit StrUtils (PadLeft und PadRight).
Das Memo musst du beim Programmende selbst nicht freigeben, das macht das Formular automatisch.
try-Böcke verwende ich in der Regel nur zusammen mit "finally". Da dabei der finally-teil immer durchlaufen wird, auch wenn im Block vorher ein Fehler aufgetreten ist, kann so sichergestellt werden, dass angeforderte Resourcen wieder freigegeben werden. In dem Beispiel kommt das mehrmals vor: Zum Beispiel wird der CSVParser erzeugt, und durch den finally-Abschnitt wird sichergestellt, dass der Parser wieder freigegeben wird. Also
Code: Alles auswählen
csv := TCSVParser.Create;
try
// tue etwas mit dem Parser
finally
// Parser wird nicht mehr benötigt
csv.free;
end;
P.S.
Das beigefügte Demo-Programm funktioniert soweit. Allerdings habe ich nicht getestet, ob das Verlängern des Arrays richtig funktioniert, wenn der vorab reservierte Block voll ist. Normalerweise ist das kein Problem, aber da die Header-Zeile der Datei ja nicht ins Datenarray eingelesen wird, muss man das im Zähler korrigieren, und da rutscht ein -1 leicht an die falsche Stelle.