AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Neuen Beitrag zur Code-Library hinzufügen Delphi csv Datei Import ClassHelper für TClientDataSet

csv Datei Import ClassHelper für TClientDataSet

Ein Thema von MaBuSE · begonnen am 26. Okt 2011 · letzter Beitrag vom 24. Mai 2019
Antwort Antwort
Seite 1 von 7  1 23     Letzte » 
Benutzerbild von MaBuSE
MaBuSE

Registriert seit: 23. Sep 2002
Ort: Frankfurt am Main (in der Nähe)
1.810 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

csv Datei Import ClassHelper für TClientDataSet

  Alt 26. Okt 2011, 20:26
Hallo,
oft kommt es vor, das man eine csv Datei ("comma seperated value" - Datei) laden möchte um die Daten zu verarbeiten.

Eine Beispiel csv Datei könnte so aussehen:
Code:
Test;"Test Test";"Test "" Test";"Test ; Test";"Test "";"" Test"
Das würde folgenden Feldern entsprechen:
Code:
Spalte 1: Test
Spalte 2: Test Test
Spalte 3: Test " Test
Spalte 4: Test ; Test
Spalte 5: Test ";" Test
Im Netz habe ich nur relativ komplizierte "Lösungen" gefunden, die das mit den Delimiter und QuoteChar richtig machen.

Aus diesem Grund habe ich mir einen kleinen ClassHelper für das TClientDataSet geschrieben.

In meiner "einfachen" Lösung mache ich mir den Umstand zunutze, das die csv Implementierung eigentlich schon im TStrings Objekt vorhanden ist. Deshalb muss ich nicht mir Pos(';', ... arbeiten.

Ich habe das TClientDataSet verwendet, da es ein vollwertiges TDataSet ist und so alle Möglichkeiten der Bearbeitung und Anzeige zu Verfügung stehen.

Folgendes kleines Beispiel soll die Benutzung demonstrieren:
  • neue VCL Anwendung erzeugen
  • TClientDataSet auf das Formular legen
  • TDataSource auf das Formular legen und mit TClientDataSet verbinden
  • TDBGrid auf das Formular legen und mit TDataSource verbinden
  • TButton auf das Formular legen
  • TButton doppelklicken
  • Die uses Anweisung oben in der Unit um meine Unit erweitern (ClientDatasetCsvClassHelper)
  • in das OnClick Ereignis folgenden Code schreiben:
      ClientDataSet1.LoadFromFile('Dateiname.txt'); (Dateiname.txt sollte durch einen gültigen Dateinamen einer *.csv Datei ersetzt werden)
  • Kopilieren und Button drücken

Diese Lösung ist so felxibel, dass auch andere Delimiter und QuoteChar verwendet werden können.
Eine evtl vorhandene Titelzeile mit Feldnamen kann auch berücksichtigt werden.
Es gibt natürlich noch viel Raum für Verbesserungen. Aber es soll ja nur ein kleines Beispiel sein.
  • nach Import Feldlängen bestimmen und Feler entsprechend kürzen
  • FeldTypen erkennen und Felder entsprechend setzen (String, Integer, TDateTime, ...)
  • Encoding (z.B. UTF8 / Unicode) als Parameter durchreichen
  • ...

Ich hoffe das es einige nützlich finden
Euer MaBuSE

Das ist der komplette Quelltext:
Delphi-Quellcode:
////////////////////////////////////////////////////////////////////////////////
// ClientDatasetCsvClassHelper
//
// 2 einfache Methoden um csv Dateien (comma seperated value Dateien) in ein
// TClientDataSet zu laden bzw. zu speichern.
//
// Der ClassHelper wurde Quick and Dirty geschrieben, und ist nicht als
// Lehrbuchbeispiel der Programmierung geeignet. Trotzdem hoffe ich, das es
// für den ein oder anderen lehrreich ist.
//
// Benutzung:
//
// - diese Unit in der uses Anweisung aufnehmen
// - ClientDataSet hat nun die 2 Methoden zur Verfügung
//
// unit TestIt;
// interface
// uses
// ...
// Dialogs, StdCtrls, Grids, DBGrids, DB, DBClient, ComCtrls,
// ClientDatasetCsvClassHelper;
// type
// TForm1 = class(TForm)
// Button1: TButton;
// DataSource1: TDataSource;
// DBGrid1: TDBGrid;
// ClientDataSet1: TClientDataSet;
// procedure Button1Click(Sender: TObject);
// end;
// ...
// implementation
// ...
// procedure TForm1.Button1Click(Sender: TObject);
// ClientDataSet1.LoadFromFile('C:\temp\Test.txt', 15);
// end;
// ...
//
// Download des neusten Quelltextes auf www.delphipraxis.net
// URL: http://www.delphipraxis.net/1132710-post1.html (url bitte anpassen)
//
// verwendete 3rd party Komponenten:
// - keine
//
// sonstige verwendete Dateien, die nicht Bestandteil von Delphi sind:
// - keine
//
////////////////////////////////////////////////////////////////////////////////
// Der Classhelper ist Freeware und darf beliebig benutzt und erweitert werden.
// Es wäre nett, wenn dann auch der geänderte Quelltext in obiges URL-Adresse
// gesendet wird. Dann haben alle was davon.
// Es wäre auch nett wenn mein (unser) Name in den Dateien enthalten bleibt.
// Der ClassHelper wird von Ihnen auf eigenes Risiko eingesetzt. Ich übernehme
// keine Haftung für Schäden die durch den Classhelper oder die Benutzung des
// Classhelper entstanden sind bzw. entstehen.
////////////////////////////////////////////////////////////////////////////////
// (C) 2011, MaBuSE, member of DelphiPraxis.net
////////////////////////////////////////////////////////////////////////////////
// ReleaseNotes:
// v1.0 - 26.10.2011 - MaBuSE: Erste Version mit Kommentaren versehen
////////////////////////////////////////////////////////////////////////////////
unit ClientDatasetCsvClassHelper;

interface

uses
  SysUtils, Classes, DB, DBClient;

type
  TClientDataSetCsvClassHelper = class helper for TClientDataSet
    procedure LoadFromFile(Filename: string; const StringLength: Integer = 100;
      const FirstLineTitle: Boolean = False;
      const Delimiter: Char = ';'; const QuoteChar: Char = '"');
    procedure SaveToFile(Filename: string; const FirstLineTitle: Boolean = False;
      const Delimiter: Char = ';'; const QuoteChar: Char = '"');
  end;


implementation

{ TClientDataSetCsvClassHelper }

// LoadFromFile importiert eine csv Datei in ein TClientDataSet.
// Dabei wird die Tabellenstruktur entsprechend der csv Datei neu erzeugt
//
// Parameter:
// Filename: string Dateiname der csv Datei
// const StringLength: Integer = 100 Länge der Felder (alle Felder sind gleich lang)
// const FirstLineTitle: Boolean = False In 1. Zeile stehen Spaltennamen
// const Delimiter: Char = ';' Delimiter trennt die einzelnen Felder
// const QuoteChar: Char = '"' QuoteChar schließt Strings ein
//
procedure TClientDataSetCsvClassHelper.LoadFromFile;
var
  slFile: TStringList;
  slRow: TStringList;
  i: Integer;
  j: Integer;
begin
  slFile := TStringList.Create;
  slRow := TStringList.Create;
  try
    slRow.Delimiter := Delimiter;
    slRow.QuoteChar := QuoteChar;
    slRow.StrictDelimiter := True;
    slFile.LoadFromFile(Filename);

    // ClientDataset Initialisieren
    if slFile.Count > 0 then
    begin
      Active := False;
      slRow.DelimitedText := slFile[0];
      FieldDefs.Clear;
      for i := 0 to slRow.Count - 1 do
      begin
        if FirstLineTitle then
        begin
          FieldDefs.Add(slRow[i], ftString, StringLength);
        end
        else
        begin
          FieldDefs.Add(Format('Field%d',[i]), ftString, StringLength);
        end;
      end;
      CreateDataSet;
      Active := True;
    end;

    // TClientDataset füllen
    DisableControls;
    for i := 0 to slFile.Count - 1 do
    begin
      slRow.DelimitedText := slFile[i];
      Append;
      for j := 0 to slRow.Count - 1 do
      begin
        Fields[j].AsString := slRow[j];
      end;
      Post;
    end;
    EnableControls;
  finally
    slFile.Free;
    slRow.Free;
  end;
end;

// SaveToFile exportiert ein TClientDataSet in eine csv Datei.
//
// Parameter:
// Filename: string Dateiname der csv Datei
// const FirstLineTitle: Boolean = False In 1. Zeile stehen Spaltennamen
// const Delimiter: Char = ';' Delimiter trennt die einzelnen Felder
// const QuoteChar: Char = '"' QuoteChar schließt Strings ein
//
procedure TClientDataSetCsvClassHelper.SaveToFile(Filename: string;
  const FirstLineTitle: Boolean; const Delimiter, QuoteChar: Char);
var
  slFile: TStringList;
  slRow: TStringList;
  i: Integer;
  c: Integer;
begin
  slFile := TStringList.Create;
  slRow := TStringList.Create;
  try
    slRow.Delimiter := Delimiter;
    slRow.QuoteChar := QuoteChar;
    slRow.StrictDelimiter := True;

    DisableControls;
    c := FieldDefs.Count;
    if FirstLineTitle then
    begin
      for i := 0 to c - 1 do
      begin
        slRow.Add(FieldDefs[i].Name);
      end;
      slFile.Add(slRow.DelimitedText);
    end;

    First;
    while not Eof do
    begin
      slRow.Clear;
      for i := 0 to c - 1 do
      begin
        slRow.Add(Fields[i].AsString);
      end;
      slFile.Add(slRow.DelimitedText);
      Next;
    end;
    slFile.SaveToFile(Filename);
    EnableControls;
  finally
    slFile.Free;
    slRow.Free;
  end;
end;

end.
Angehängte Dateien
Dateityp: pas ClientDatasetCsvClassHelper.pas (6,0 KB, 115x aufgerufen)
(°¿°) MaBuSE - proud to be a DP member
(°¿°) MaBuSE - proud to be a "Rüsselmops" ;-)

Geändert von MaBuSE (26. Okt 2011 um 20:32 Uhr) Grund: URL in Quelltext angepasst
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#2

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 27. Okt 2011, 07:46
Geht das auch mit einer CSV-Datei der Form
Code:
Test;"Zeile 1 von Test
Zeile 2 von Test";Test
Daraus muss ein Record mit drei Feldern werden.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
6.808 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 27. Okt 2011, 08:45
Geht das auch mit einer CSV-Datei der Form
Code:
Test;"Zeile 1 von Test
Zeile 2 von Test";Test
Daraus muss ein Record mit drei Feldern werden.
Das hat allerdings weniger mit dem ClassHelper zu tun, als mit der Implementation von SetDelimitedText in TStringList. MaBuSE geht einfach davon aus, daß diese Implementation korrekt ist.

Aber was heißt schon korrekt. Ein verbindliches Format für CSV gibt es nicht (nur RFC 4180) und ich habe selbst schon mehrfach eigene Implementierungen schreiben müssen, weil die Kollegen, die die erzeugenden Programme geschrieben haben, einfach ihre Hausaufgaben nicht gemacht hatten.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von MaBuSE
MaBuSE

Registriert seit: 23. Sep 2002
Ort: Frankfurt am Main (in der Nähe)
1.810 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 27. Okt 2011, 09:10
Geht das auch mit einer CSV-Datei der Form
Code:
Test;"Zeile 1 von Test
Zeile 2 von Test";Test
Daraus muss ein Record mit drei Feldern werden.
Nein, das geht nicht.
In csv Dateien bedeutet das Zeilenende in der Regel dass ein neuer Datensatz beginnt. Sprich: Es sind keine Zeilenunbrüche in Feldern erlaubt.

In meiner Implementierung kopiere ich jede einzelne Zeile in ein TStrings und hole dann die einzelnen Felder aus diesem heraus.
Mit meiner Methode geht das also auf keinen Fall.

Ich habe mir das ursprünglich geschrieben um bestimmte Log-Dateien auszuwerten.
Für die CodeLib habe ich dann noch SaveToFile ergänzt.

Meine Intention, das in die CodeLib zu stellen, war zu zeigen, dass es einen relativ einfachen Weg gibt csv Dateien zu importieren.

Letztendlich reicht schon folgender Quellcode aus um eine csv-Datei zu lesen und auf alle einzelnen Felder zuzugreifen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  slFile, slRow: TStringList;
  i, j: Integer;
begin
  slFile := TStringList.Create;
  slRow := TStringList.Create;
  slRow.Delimiter := ';';
  slRow.QuoteChar := '"';
  try
    slFile.LoadFromFile('dateiname.csv');
    for i := 0 to slFile.Count - 1 do
    begin
      slRow.DelimitedText := slFile[i]; // wandelt eine csv-Zeile um -> jedes Feld bekommt eine eigene Zeile in slRow
      for j := 0 to slRow.Count - 1 do
      begin
        Memo1.Lines.Add(Format('Row:%3d Col:%2d: Value:%s', [i, j, slRow[j]]));
      end;
    end;
  finally
    slFile.Free;
    slRow.Free;
  end;
end;
Das ist ein gutes Beispiel für KISS (keep it stupid simple).

Ich hoffe diese Info hilft Dir.
(°¿°) MaBuSE - proud to be a DP member
(°¿°) MaBuSE - proud to be a "Rüsselmops" ;-)

Geändert von MaBuSE (27. Okt 2011 um 09:27 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von MaBuSE
MaBuSE

Registriert seit: 23. Sep 2002
Ort: Frankfurt am Main (in der Nähe)
1.810 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 27. Okt 2011, 09:35
Auf der Basis des Beispiels in dem vorherigen Beitrag habe ich noch einen Class Helper geschrieben.

Damit kann man ein TStringGrid mit einer csv Datei befüllen.

Beispiel:
Delphi-Quellcode:
...
uses StringGridCsvClassHelper;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  StringGrid1.LoadFromFile('Dateiname.csv');
end;
...
Das ist ein einfaches Beispiel für Class Helper und csv Import.
Vieleicht hilft's wem.

mfg
MaBuSE

ps: Hier ist die Unit des ClassHelpers:

Delphi-Quellcode:
unit StringGridCsvClassHelper;
// use at your own risk
interface

uses
  SysUtils, Classes, Grids;

type
  TStringGridCsvClassHelper = class helper for TStringGrid
    procedure LoadFromFile(Filename: string;
      const Delimiter: Char = ';'; const QuoteChar: Char = '"');
  end;

implementation

{ TStringGridCsvClassHelper }

procedure TStringGridCsvClassHelper.LoadFromFile(Filename: string;
  const Delimiter: Char = ';'; const QuoteChar: Char = '"');
var
  slFile: TStringList;
  slRow: TStringList;
  i: Integer;
  j: Integer;
begin
  slFile := TStringList.Create;
  slRow := TStringList.Create;
  slRow.Delimiter := Delimiter;
  slRow.QuoteChar := QuoteChar;
  try
    slFile.LoadFromFile(Filename);

    // StringGrid Init
    if slFile.Count > 0 then
    begin
      slRow.DelimitedText := slFile[0];
      FixedCols := 0;
      FixedRows := 0;
      ColCount := slRow.Count;
      RowCount := slFile.Count;
    end;

    // Fill StringGrid
    for i := 0 to slFile.Count - 1 do
    begin
      slRow.DelimitedText := slFile[i];
      for j := 0 to slRow.Count - 1 do
      begin
        Cells[j,i] := slRow[j];
      end;
    end;
  finally
    slFile.Free;
    slRow.Free;
  end;
end;

end.
(°¿°) MaBuSE - proud to be a DP member
(°¿°) MaBuSE - proud to be a "Rüsselmops" ;-)
  Mit Zitat antworten Zitat
H.Bothur

Registriert seit: 25. Jun 2012
132 Beiträge
 
#6

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 7. Jun 2017, 14:58
Moin,

sorry wenn ich hier so was altes raussuche aber das hilft mir gerade sehr weiter. Allerdings ...

1) ich müsste den Trenner von Semikolon auf TAB ändern .. das wäre dann imho hier die "#9" statt "';'"
Delphi-Quellcode:
type
  TClientDataSetCsvClassHelper = class helper for TClientDataSet
    procedure LoadFromFile(Filename: string; const StringLength: Integer = 100;
      const FirstLineTitle: Boolean = False;
      const Delimiter: Char = #9; const QuoteChar: Char = '"');
    procedure SaveToFile(Filename: string; const FirstLineTitle: Boolean = False;
      const Delimiter: Char = #9; const QuoteChar: Char = '"');
  end;
2) Was mache ich wenn ich nicht auf QuoteChars reagieren möchte ? Die Datei die ich habe hat keinen Texttrenner, dafür aber mitten im Text Anführungsstriche.

Hans
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#7

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 7. Jun 2017, 15:04
Statt dem " ein Zeichen nehmen, das nicht vorkommt?

z. B. #7
  Mit Zitat antworten Zitat
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.552 Beiträge
 
Delphi 6 Enterprise
 
#8

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 7. Jun 2017, 15:16
Oder alles mit QuoteChar zu tun hat aus dem Classhelper entfernen?

Probele können aber glaub ich auftreten, wenn du Leerzeichen in deinen Daten hast.
Ralph
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.325 Beiträge
 
Delphi 7 Personal
 
#9

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 7. Jun 2017, 15:18
Den QuoteChar kannst Du ja selbst definieren, meist schließen sich ja ' und " gegenseitig aus.
Bei den SteuerZeichen STX,ETX,EOT...(x00..x1F) hab ich mich schon des Öfteren verhaspelt.
U.U wäre xFF eine gute Wahl.

Gruß
K-H

P.S.
Probele können aber glaub ich auftreten, wenn du Leerzeichen in deinen Daten hast.
Sollte eigentlich nicht der Fall sein. Der Stolperstein ist eher der Zeilenumbruch.
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector

Geändert von p80286 ( 7. Jun 2017 um 15:22 Uhr)
  Mit Zitat antworten Zitat
H.Bothur

Registriert seit: 25. Jun 2012
132 Beiträge
 
#10

AW: csv Datei Import ClassHelper für TClientDataSet

  Alt 7. Jun 2017, 15:19
Nicht ganz sauber - aber ich ersetzte jetzt das " durch ein '

Hans
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:19 Uhr.
Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf