![]() |
CSVViewer - Zum Betrachten von CSV-Dateien
Liste der Anhänge anzeigen (Anzahl: 2)
Nichts großes, weltbewegendes. Nur ein kleines Programm, um CSV-Dateien betrachten zu können, ohne dass man immer gleich Excel oder OpenOffice starten muss. So was wollte ich schon immer mal für die Backupdateien meiner Adressdatenbank machen und jetzt habe ich es gemacht. Es war eigentlich nur für mich zu privat Zwecken gedacht, aber eventuell findet es ja noch jemand anders nützlich, wenn nicht das Programm, dann vielleicht den Code, obwohl auch dieser war in seiner Grundform in zwanzig Minuten hingehackt.
Das Programm sollte selbsterklärend sein. Mit einem Rechtsklick auf den Listview öffnet sich ein Kontextmenü, mit dem man entweder die eine Zelle/Feld in die Zwischenablage kopieren kann oder die ganze Zeile. |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Hi Luckie,
vielen Dank für den Quelltext! War schon immer zu faul für sowas :oops: ! Mein D7pe kennt die Zeile (in TfrmMain.FillListview) mit
Delphi-Quellcode:
nicht und mag die Zeile für das automatische Spaltenbreitensetzen mit
Delimitedline.StrictDelimiter := True;
Delphi-Quellcode:
nicht (Absturz mit "Listenindex überschreitet das Maximum (x)").
lvCSVFile.Columns.Items[j].Width := ColumnTextWidth;
Abhilfe: Beide Zeilen (in TfrmMain.FillListview) auskommentieren und nach
Delphi-Quellcode:
die Zeile
Progressbar1.Position := 0;
Delphi-Quellcode:
einfügen.
for i:=0 to lvCSVFile.Columns.count -1 do lvCSVFile.Columns[i].width:= -1;
MfG |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Entwickelt hab eich mit D2006. Und ColumnTextWidth ist nur eine Konstante für -1.
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Delphi-Quellcode:
statt
lvCSVFile.Columns.Items[j].Width := -1;
Delphi-Quellcode:
führt in D7pe zum gleichen Absturz :oops:
lvCSVFile.Columns.Items[j].Width := ColumnTextWidth;
MfG |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Es ist ja auch egal, ob man eine Konstante niummt oder den Wert direkt zuweist.
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Jetzt stellt sich die Frage, warum das bei mir nicht zum Absturz führt. Ist deine CSV-Datei eventuell nicht in Ordnung oder so?
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Leider kann der CSVViewer nicht alle CSV-Dateien nach
![]() Folgendes ist nach RFC ein gültige CSV-Datei
Code:
und sollte folgendes ergeben
ID;TEXT
1;Test 2;"Test" 3;"Test""Test" 4;"Test Test Test" 5;Last
Code:
Wenn man mit dem "Microsoft Text-Treiber" die CSV öffnet, dann wird die auch korrekt verarbeitet
ID TEXT
1 Test 2 Test 3 Test"Test 4 Test Test Test 5 Last |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Was macht mein Programm daraus?
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Code:
ID TEXT
===== ========= 1 Test 2 Test 3 Test"Test 4 Tes Test Test" 5 Last |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Dann ist das ein Bug von Delphi, dass sich TStringList nicht an das RFC hält. Lösung wäre, die Datei selber zu parsen, aber dazu war ich zu faul. Allerdings, man könnte noch mal probieren, was Explode daraus macht.
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Allerdings musst du dafür die CSV-Datei entweder in ein temp. Verzeichnis kopieren, oder die Schema.ini Datei in das CSV-Verzeichnis erzeugen Wobei die erste Variante zu bevorzugen ist :) |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Das ist quasi der gesamte "Aufwand"
Delphi-Quellcode:
und hier die Arbeit
con1 : TADOConnection;
tbl1 : TADOTable; ds1 : TDataSource; dbg1 : TDBGrid; tbl1.Connection := con1; ds1.DataSet := tbl1; dbg1.DataSource := ds1;
Delphi-Quellcode:
procedure TForm1.FileOpen1Accept( Sender : TObject );
var DataFile : _FileName; // <- ist ein Spezial-Record für Dateinamen :o) SchemaFile : _FileName; idx : Integer; begin if con1.Connected then con1.Close; DataFile := FileOpen1.Dialog.FileName; SchemaFile := DataFile; SchemaFile.FileName := 'schema.ini'; with TIniFile.Create( SchemaFile ) do try WriteString( DataFile.FileName, 'Format', 'Delimited(;)' ); finally Free; end; con1.Provider := 'MSDASQL'; con1.ConnectionString := 'Driver={Microsoft Text-Treiber (*.txt; *.csv)};Extensions=asc,csv,tab,txt;'; con1.DefaultDatabase := DataFile.DirName.FullName; tbl1.TableDirect := True; tbl1.TableName := DataFile.FileName; tbl1.Open; end; |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Und als visuelle Komponente habe ich dann einen TTable?
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Eine TTable ist nicht visuell, eher eine DBGrid
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
OK, dann habe ich noch nicht verstanden wie ich das angezeigt bekomme. Wird dann ein DBGrid mit dem TTable verknüpft?
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Ja über eine TDataSource
DBGrid->DataSource->DataSet |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Steht doch bei mir im ersten CodeTeil
Ist aber getrennt, weil man das a) auf die Form klatscht und b) die Zuordnung über den OI macht |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Ah ja, jetzt sind mir auch die Bezeichnungen klar. ;)
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Ihr macht mir echt Spaß!
Aus einem kleinen CSVViewer flugs ein Monster mit DatenbankTrallala gemacht :evil: Und Tschüss :oops: |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Wie sehen bei dir denn kleine Programme aus? Einzeiler mit Hallo Welt? Und alles andere ist dann schon Overkill? |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
|
AW: CSVViewer - Zum Betrachten von CSV-Dateien
@vergessen
Monster? Das ist der unaufwändigste und naheliegenste Weg. |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Von D7pe mal kurz auf D7pro aufrüsten? Luckies Original-Source lief mit ein paar kleinen Änderungen auch mit D7pe. Mei mei oh mei... |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Kann aber nicht alle CSV Dateien nach RFC 4180 korrekt verarbeiten.
Wenn du das nachbauen möchtest, dann hast du schon ein kleineres Monster. Für mich zählt neben DRY auch DRW (Don't Reinvent Wheels) |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Sollte mit StringReplace wohl zu machen sein, denke ich mir einfach mal... @Luckie: Unter welcher Lizenz ist/steht Dein "CSVViewer"-Sourcecode? MfG |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Luckie hat ja (im Kern) eh "nur" die Methoden von TStringList benutzt.
Die kannst du aber nicht nehmen, weil die das nicht unterstützen. Somit muss ein eigener Parser her, der sich aber in Grenzen hält, weil du eh nur auf nicht mal eine Handvoll Zeichen prüfen mußt. Delimiter Quotes Zeilenende Das sollte sich eigentlich gut bewerkstelligen lassen :) |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Eine selbstgeschriebene Function reinwurschteln geht wohl neuerdings nicht mehr? Ahjahhh. Danke für die Aufklärung! mei oh mei oh mei! |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Zitat:
Das Problem ist, dass die TStringList eben stur mit dem Zeilenende arbeitet. Eine CSV-Datei kann aber innerhalb eines Feldes auch Zeilenumbrüche beinhalten, und da macht die TStringList eben schlapp. (Die TStringList ist auch nur für das Aufbrechen einer Zeile benutzt worden, nicht für die gesamte CSV-Datei als Ganzes) Also eine eigene Klasse bauen (TCSVData) und parsen Hab da mal was auf die Schnelle zusammengehackt:
Delphi-Quellcode:
unit CSVData;
interface type TCSVData = class private FData : array of array of string; FDelim : Char; FQuote : Char; function GetRows : Integer; function GetCols : Integer; function GetCell( Row, Col : Integer ) : string; procedure SetCell( Row, Col : Integer; const Value : string ); public destructor Destroy; override; procedure LoadFromFile( const FileName : string ); property Cell[Row, Col : Integer] : string read GetCell write SetCell; property Rows : Integer read GetRows; property Cols : Integer read GetCols; property Delim : Char read FDelim write FDelim; property Quote : Char read FQuote write FQuote; end; implementation uses Classes; { TCSVData } destructor TCSVData.Destroy; begin SetLength( FData, 0, 0 ); inherited; end; function TCSVData.GetCell( Row, Col : Integer ) : string; begin Result := FData[Row, Col]; end; function TCSVData.GetCols : Integer; begin if Rows > 0 then Result := Length( FData[0] ) else Result := 0; end; function TCSVData.GetRows : Integer; begin Result := Length( FData ); end; procedure TCSVData.LoadFromFile( const FileName : string ); var Data : TStrings; Val : string; MyChar : Char; LastChar : Char; QuotePart : Boolean; Col : Integer; Row : Integer; MaxCol : Integer; begin Data := TStringList.Create; try Data.LoadFromFile( FileName ); LastChar := #0; QuotePart := False; Val := ''; MaxCol := 0; Col := 0; Row := 0; // Jedes Zeichen durchlaufen for MyChar in Data.Text do begin if ( MyChar = Quote ) then begin // QuotePart wechselt den Status QuotePart := not QuotePart; // Befinden wir uns im QuotePart und das letzte Zeichen // war das Quote-Zeichen, dann handelt es sich um eine // Verdoppelung und wir hängen das Quote-Zeichen an // den Puffer if QuotePart and ( LastChar = Quote ) then Val := Val + Quote; end else if not QuotePart and ( MyChar = Delim ) then begin // Sind noch nicht genug Zeilen da ... if high( FData ) < Row + 1 then // ... dann auf Verdacht schon mal 10 hinzufügen SetLength( FData, Row + 10 ); // Sind noch nicht genug Spalten da ... if high( FData[Row] ) < Col + 1 then // ... dann auf Verdacht schon mal 10 hinzufügen SetLength( FData[Row], Col + 10 ); // Wert eintragen FData[Row, Col] := Val; // Puffer leeren Val := ''; // Spalte hochzählen Inc( Col ); end else if not QuotePart and ( ( MyChar = #13 ) or ( MyChar = #10 ) ) then begin // Haben wir CR LF gefunden ... if ( MyChar = #10 ) and ( LastChar = #13 ) then begin // Sind noch nicht genug Zeilen da ... if high( FData ) < Row + 1 then // ... dann auf Verdacht schon mal 10 hinzufügen SetLength( FData, Row + 10 ); // Die Anzahl der Spalten steht jetzt fest SetLength( FData[Row], Col + 1 ); // MaxCol merken if Col > MaxCol then MaxCol := Col; // Wert eintragen FData[Row, Col] := Val; // Puffer leeren Val := ''; // Zeile hochzählen Inc( Row ); // Neue Zeile => erste Spalte Col := 0; end; end else // Das aktuelle Zeichen an den Puffer hängen Val := Val + MyChar; // Das letzte Zeichen merken LastChar := MyChar; end; SetLength( FData, Row ); // Das ist eigentlich nur notwendig, wenn die CSV-Datei falsch aufgebaut ist // und unterschiedliche Anzahl von Spalten in den Zeilen aufweist // Dieses ist allerdings nicht RFC-konform, aber wir wollen mal nicht so sein for Row := low( FData ) to high( FData ) do SetLength( FData[Row], MaxCol + 1 ); finally Data.Free; end; end; procedure TCSVData.SetCell( Row, Col : Integer; const Value : string ); begin FData[Row, Col] := Value; end; end. |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Danke. Aber im Moment hab eich andere Probleme. Mein Monitor hat schlapp gemacht und die Grafikkrate unterstützt die native Auflösung des neuen Monitores nicht. :evil: Jetzt muss auch erstmal eine neue Grafikkarte für günstig Geld her. :(
Aber ich denke heute Abend habe ich auch das Problem gelöst. |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Hallo :hi:
ich habe schon vor einiger Zeit meinen ![]() Es ist eine MDI-Anwendung und kann CSV korrekt parsen (Quotezeichen werden beachtet). Nur den Sprung vom Viewer zum echten Editor hat das Tool nie geschafft... |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Den Sprung wird meiner auch nicht schaffen, aber das soll er auch gar nicht.
Sagt mal, warum seid ihr alle so breit? ;) |
AW: CSVViewer - Zum Betrachten von CSV-Dateien
Liste der Anhänge anzeigen (Anzahl: 1)
Danke Luckie, für die Vorarbeit. Ganz praktisch, aber zuuu langsam. Ich habe die Methode FillListview mal dahingehend angepasst, dass die Daten wirklich schnell verarbeitet werden. Jetzt benötigt nur noch die Berechnung der Spaltenbreite eine gewisse Zeit ;)
...:cat:... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:03 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz