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.