CSV in ListView lesen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Aphadias
Beiträge: 124
Registriert: Mi 28. Okt 2015, 18:28

CSV in ListView lesen

Beitrag von Aphadias »

Moin,

nach langer Zeit muss ich mich doch mal wieder melden :lol:

Ich möchte gerne eine CSV Datei in meine ListView lesen und danach in meiner vorhandenen Datenbank speichern. Ich habe 0 Plan wie ich das angehen soll. Es muss ja irgend wie eine for Schleife gebaut werden und sobald in der CSV ein ; kommt muss er i ein hoch rechnen oder?

bei PHP war es mit explode irgend wie leichter :lol:

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6197
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: CSV in ListView lesen

Beitrag von af0815 »

es gibt viel Möglichkeiten das zu machen. Hängt auch von der Qualität des csv ab :-)

CSV Kann man direkt als Datenbank lesen. http://wiki.freepascal.org/CSV

fpSpreadsheet kann es auch lesen http://wiki.freepascal.org/FPSpreadsheet

In ein StringList selbst einlesen und die richtigen Delimiter setzen http://forum.lazarus.freepascal.org/ind ... ic=17345.0
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Aphadias
Beiträge: 124
Registriert: Mi 28. Okt 2015, 18:28

Re: CSV in ListView lesen

Beitrag von Aphadias »

Danke für die schnelle Antwort ^^

Mit der Datenbank das habe ich schon mal gemacht. Aber dort habe ich ein DBGrid genommen weil ich damals schon dran gescheitert bin es in einer ListView zu schreiben. Nur dieses mal muss es in eine ListView ^^
Spreadsheet hatte ich mir auch schon angesehen... aber irgend wie zu kompliziert :roll:
Ich schaue mir es mal mit der StringList an. Mal schauen wie das wird

Warf
Beiträge: 1907
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: CSV in ListView lesen

Beitrag von Warf »

Die Subitems property eines ListItems ist ein TStrings, also müsste sowas gehen:

Code: Alles auswählen

with ListView1.Items.Add do
begin
  SubItems.Delimiter := ',';
  SubItems.StrictDelimiter := True;
  SubItems.DelimitedText := CSVLine;
  Caption := SubItems[0];
  SubItems.Delete(0);
end;


Die letzen zwei zeilen kannst du dir sogar sparen wenn du die erste spalte einfach unsichtbar machst und nur mit dem subitems arbeitest (mache ich gerne um dort zusätzliche Informationen wie Indexe oder so zu speichern).

Das einzige was du noch separat machen musst ist der Header (also die erste zeile)

wp_xyz
Beiträge: 4864
Registriert: Fr 8. Apr 2011, 09:01

Re: CSV in ListView lesen

Beitrag von wp_xyz »

Im Anhang findest du ein Beispiel, wie eine CSV-Datei (geklaut von https://cerc.blackboard.com/Page/1189) in ein TListView eingelesen werden kann. Es gibt wahrscheinlich so viele Möglichkeiten wie Programmierer...

Da du offenbar neu in Pascal bist, habe ich die Datei zeilenweise mit Hilfe der klassichen Readln-Anweisungen eingelesen. Jede Zeile steht dann immer in einem String s, der mit dessen Helper-Methode .Split(',') an den Komma-Positionen zerhackt wird (das Gegenstück zum php-Explode); die Teile stehen dann in einem String-Array. Wenn man das mit der 1. Zeile macht, die die Überschriften enthält, hat man alle Informationen, um die Spalten der Listview zu erzeugen. Anschließend liest man den Rest der Datei und verteilt die zerhackten Strings vom Array in die Spalten der ListView, wobei zu beachten ist, dass in der 1.Spalte immer die Caption der ListItems steht, und die folgenden Strings in den SubItems.

P.S.
Die Warf-Methode ist gefällt mir besser als mein Beispiel. Aber ich wollte unbedingt das String.Split erwähnen, da im 1. Beitrag das Fehlen von php's explode bedauert wird.
Dateianhänge
csv_to_listview.zip
(2.89 KiB) 124-mal heruntergeladen

Frank Ranis
Beiträge: 201
Registriert: Do 24. Jan 2013, 21:22

Re: CSV in ListView lesen

Beitrag von Frank Ranis »

Hallo wp_xyz

ich muß dir mal ein dickes Lob aussprechen.

Deine Kern-Routine hast Du super dokumentiert , die kann man in 10,15,20 Jahren noch mal rauskramen und weis sofort was Sache ist.

Code: Alles auswählen

procedure TForm1.ReadCSVToListView(AFileName: String);
var
  F: TextFile;
  s: String;
  sa: TStringArray;
  listitem: TListItem;
  i: Integer;
begin
  // Neuzeichnen der ListView beim Hinzufügen von neuen Einträgen unterbinden.
  // Das würde alles sehr verlangsamen (natürlich nur bei großen Dateien).
  ListView1.Items.BeginUpdate;
 
  AssignFile(F, FILE_NAME);
  Reset(F);
 
  // TListView hat Spalten nur im Viewstyle vsReport
  ListView1.ViewStyle := vsReport;
 
  // Feldnamen einlesen - die stehen in der 1. Zeile
  // - Zeile einlesen
  ReadLn(F, s);
  // - In die einzelnen felder, die durch Komma getrennt sind, aufspalten
  sa := s.Split(',');
  // - Für jedes Feld eine Spalte erzeugen
  for i:=0 to High(sa) do
    with ListView1.Columns.Add do begin
      Caption := sa[i];
      Width := 150;
    end;
 
  // Nun den Rest der Datei einlesen
  while not EoF(F) do begin
    // - Aktuelle Zeile einlesen
    ReadLn(F, s);
    // - In die einzelnen Felder aufspalten
    sa := s.Split(',');
    // - ListItem für diesen Record erzeugen
    listitem := ListView1.Items.Add;
    // - Das 1.feld geht in die Caption des ListItem
    listitem.Caption := sa[0];
    // - Alle folgenden Felder gehen in die SubItems des ListItem
    // Achtung: Nummerierung beginnt hier bei 1, weil 0 ja schon verwendet wurde!
    for i := 1 to High(sa) do
      listitem.SubItems.Add(sa[i]);
  end;
 
  // Neuzeichnen der Listview wieder aktivieren und anstoßen.
  ListView1.Items.EndUpdate;
end;                     
 


Genau so wünscht man sich jeden Democode .

Gruß

Frank
www.flz-vortex.de

Warf
Beiträge: 1907
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: CSV in ListView lesen

Beitrag von Warf »

Noch ein kleiner tipp, Pack das Begin-End Update in ein Try-Finally:

Code: Alles auswählen

  ListView1.Items.BeginUpdate;
  try
    ...
  finally
    ListView1.Items.EndUpdate;
  end;


Sonst bekommst du eventuell in der Funktion einen Fehler (z.B. Datei lässt sich nicht öffnen) und durch die Exception wird EndUpdate nicht aufgerufen, was dazu führt das dein ListView sich nicht mehr aktualisieren kann. Macht also das gesammte Control nutzlos

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: CSV in ListView lesen

Beitrag von Timm Thaler »

Code: Alles auswählen

    for i := 1 to High(sa) do
      listitem.SubItems.Add(sa[i]);
  end;


Was passiert, wenn in den Zeilen mehr Zellen vorhanden sind als im Header? Werden dann Zellinhalte in nicht vorhandene Subitems geschrieben?

Kann ja vorkommen, dass eine CSV fehlerhaft ist.

Warf
Beiträge: 1907
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: CSV in ListView lesen

Beitrag von Warf »

Timm Thaler hat geschrieben:Was passiert, wenn in den Zeilen mehr Zellen vorhanden sind als im Header? Werden dann Zellinhalte in nicht vorhandene Subitems geschrieben?

Kann ja vorkommen, dass eine CSV fehlerhaft ist.


Gibt es weniger Subitems als Colums werden die restlichen Colums leer gefüllt, ich denke mal wenn es mehr gibt wird alles was übersteht einfach ignoriert/nicht gezeichnet (habs aber nicht getestet und hängt natürlich auch vom WS ab)

Aphadias
Beiträge: 124
Registriert: Mi 28. Okt 2015, 18:28

Re: CSV in ListView lesen

Beitrag von Aphadias »

Danke erst mal.

Leider funktioniert es bei mir noch nicht so wie es soll. Meine ListView soll im Caption bereich nicht beschrieben werden. Dazu soll es nur die erste Spalte beschrieben werden und als Split habe ich "

Problem macht mir eigentlich nur die erste Spalte. Eigentlich verstehe ich die For-Schleife so das er dafür sorgt ein nach unten zu gehen. Aber er geht wohl immer nach rechts.

Zur meiner Listview. Die hat ca 17 Spalten aber nur die erste soll beschrieben werden.

oder liegt es an der csv Datei? Die sieht ca. so aus

Text Art; Wort Wort, Schrift, Text"
Text Art; Wort Wort, Schrift, Text"
Text Art; Wort Wort, Schrift, Text"

und so soll es in einer Spalte auch untereinander stehen

Warf
Beiträge: 1907
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: CSV in ListView lesen

Beitrag von Warf »

Aphadias hat geschrieben:Danke erst mal.

Leider funktioniert es bei mir noch nicht so wie es soll. Meine ListView soll im Caption bereich nicht beschrieben werden. Dazu soll es nur die erste Spalte beschrieben werden und als Split habe ich "

Problem macht mir eigentlich nur die erste Spalte. Eigentlich verstehe ich die For-Schleife so das er dafür sorgt ein nach unten zu gehen. Aber er geht wohl immer nach rechts.

Zur meiner Listview. Die hat ca 17 Spalten aber nur die erste soll beschrieben werden.

oder liegt es an der csv Datei? Die sieht ca. so aus

Text Art; Wort Wort, Schrift, Text"
Text Art; Wort Wort, Schrift, Text"
Text Art; Wort Wort, Schrift, Text"

und so soll es in einer Spalte auch untereinander stehen


Dafür ist CSV nicht gedacht. Ist es immer einzeilig oder gibt es auch einträge die Mehrzeilig sein können.
Wenn es immer Einzeilig ist, vergiss die " und lies es einfach in eine TStringList ein und Iteriere dann über die Zeilen. Wenn es Mehrzeilig sein kann, kannst du entweder um es effizient zu gestalten einen Parser bauen oder einfach den ganzen Text spliten (und dann trim auf den einzelnen Elementen um die am anfang newlines wegzubekommen) und dann durchzuiterieren. Das braucht dann aber zwei Durchläufe (split muss einmal den gesamten Inhalt durchsuchen und du am ende musst jeden eintrag in den Listview einbauen).

Beispiel für das zweite:

Code: Alles auswählen

var sl: TStringList;
s: string;
begin
  sl:=TStringList.Create;
  try
    sl.LoadFromFile('csvFile');
    sl.Delimiter = '"';
    sl.StrictDelimiter := True;
    sl.DelimitedText := sl.Text;
    ListView1.BeginUpdate;
    try
      for s in sl do
        with ListView1.Items.Add do
           SubItems.Add(s.Trim);
    finally
      ListView1.EndUpdate;
    end;
  finally
    sl.Free;
  end;
end;

wp_xyz
Beiträge: 4864
Registriert: Fr 8. Apr 2011, 09:01

Re: CSV in ListView lesen

Beitrag von wp_xyz »

Aphadias hat geschrieben:Zur meiner Listview. Die hat ca 17 Spalten aber nur die erste soll beschrieben werden.

Jetzt hast du mich komplett abgehängt: Wieso 17 Spalten, wenn du nur die erste beschreiben willst? Willst du jede Zeile der CSV-Datei unzerlegt komplett in der 1.Spalte anzeigen? Und du willst die Captions nicht beschreiben. Sollen die leer bleiben? Warum nimmst du dann überhaupt den vsReport Style der Listview und nicht vsList? Oder stehen da schon andere Informationen?

Bitte mache eine vernünftige Beschreibung deines Problems, vielleicht eine Skizze dazu. So verstehe ich nur Bahnhof.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6197
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: CSV in ListView lesen

Beitrag von af0815 »

Aphadias hat geschrieben:oder liegt es an der csv Datei? Die sieht ca. so aus
Text Art; Wort Wort, Schrift, Text"
Text Art; Wort Wort, Schrift, Text"
Text Art; Wort Wort, Schrift, Text"

Das ist keine CSV, das ist kunterbunter Müll. Und genauso wie beim Müll, den muss man von Hand aus zerlegen, damit man ihn recyclen kann.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Aphadias
Beiträge: 124
Registriert: Mi 28. Okt 2015, 18:28

Re: CSV in ListView lesen

Beitrag von Aphadias »

wp_xyz hat geschrieben:
Aphadias hat geschrieben:Zur meiner Listview. Die hat ca 17 Spalten aber nur die erste soll beschrieben werden.

Jetzt hast du mich komplett abgehängt: Wieso 17 Spalten, wenn du nur die erste beschreiben willst? Willst du jede Zeile der CSV-Datei unzerlegt komplett in der 1.Spalte anzeigen? Und du willst die Captions nicht beschreiben. Sollen die leer bleiben? Warum nimmst du dann überhaupt den vsReport Style der Listview und nicht vsList? Oder stehen da schon andere Informationen?

Bitte mache eine vernünftige Beschreibung deines Problems, vielleicht eine Skizze dazu. So verstehe ich nur Bahnhof.


Ich versuche es mal bildlich zu erklären. Die ListView ist dazu da um Materialien in eine Datenbank zu speichern bzw auszulesen. Diese Materialien haben Chargen Abläufe Nummer usw... Sprich in der 1. Spalte kommt das Material 2. Spalte wieviel davon da sein soll 3. Wie viel da ist 4. Charge usw usw usw.. Die CSV Liste soll nur die Materialien enthalten. Sozusagen möchte ich das beim 1. Start der Nutzer die Materialien alle einlesen kann (aus der CSV-Liste) und danach zu jedem Material die Charge Datum usw einschreiben kann (weil es bei jedem Unterschiedlich ist). Deswegen soll nur die 1. Spalte aufgelistet werden weil der Name des Materials bei jedem gleich ist aber alle anderen Daten immer anders sind. Also eine Vorabmaske zur Arbeitserleichterung.

Die Captions sind schon bei der Erstellung der ListView vorgegeben und brauchen deswegen nicht beschrieben werden. Dort stehen die Reiter drin wie eben erwähnt.....

ist die Erklärung jetzt etwas einsichtiger?

wp_xyz
Beiträge: 4864
Registriert: Fr 8. Apr 2011, 09:01

Re: CSV in ListView lesen

Beitrag von wp_xyz »

Ja, so ist es klar.

Studiere mal das beigefügte Demo. Vielleicht kannst du darauf aufbauen.
Dateianhänge
forum_listview.zip
(2.27 KiB) 115-mal heruntergeladen

Antworten