![]() |
CSV Dateien einlesen
Hallo Community,
das einlesen von csv - Dateien in Delphi 2007 Prof. funktionierte tadellos. Jetzt mit XE3 ??? Alles versucht, wer kann helfen... Problem ist das keine Werte ins Grid eingetragen werden. Es kommt keine Fehlermeldung und im Grid Spalte0,Zeile0 stehen Chinesische Zeichen... Hier die aktuelle Source...
Delphi-Quellcode:
:pale:procedure T_Rezepteditor.FormShow(Sender: TObject); var z: single; x,y: integer; t: string; i: Integer; csvReader : TCSVReader; sData : TFileStream; begin // Mit Entertaste weiter KeyPreview := True; // Dateiname t:=Label1.Caption; sData := TFileStream.Create(t,fmOpenRead); csvReader := TCSVReader.Create (sData, ';'); csvReader.First; try StringGrid1.ColCount:=csvReader.ColumnCount; y:=-1; // Zeile while not csvReader.Eof Do begin y:=y+1; StringGrid1.RowCount:=y+1; for x:=0 to csvReader.ColumnCount - 1 Do StringGrid1.Cells[x,y]:=(csvReader.Columns[x]); csvReader.Next; end; finally csvReader.Free; sData.Free; end; end; |
AW: CSV Dateien einlesen
Vermutlich ist TCSVReader nicht unicode-fähig.
|
AW: CSV Dateien einlesen
Die Vermutung liegt nahe...
Gibt es Alternativen ? |
AW: CSV Dateien einlesen
Ist das das Ding aus der DP? Dann liegt der Source doch vor, müsste man halt mal reinschauen und anpassen.
|
AW: CSV Dateien einlesen
|
AW: CSV Dateien einlesen
Tja dann lasst uns mal schauen...
Was muss angepasst werden?
Delphi-Quellcode:
Unit csCSV;
(****************************************************************************** * CSV Reader Klasse * * Liest eine CSV-Datei ein und ermöglicht Zugriff auf die einzelnen Elemente * * jeder Zeile. * * Eine CSV ('Comma Separated Values' oder 'Character Separated Values' ist * * ein Format, um Tabellen in einer Text-Datei zu speichern. * * Dabei werden die einzelnen Elemente einer Tabellenzeile durch ein frei * * wählbares Zeichen getrennt. In Deutschland ist dies üblicherweise das * * Semikolon, im englischsprachigen Raum das Komma (daher der Name). * * Strings werden druch Quotes '"' eingeschlossen, ein Quote innerhalb eines * * Strings wird verdoppelt. * * Beispiel (Trennzeichen';'): * * "Text";123;"Text mit ""Quotes"" und Semikolon;";;Auch ein Text;345.657 * * * * Der Code ist so trivial, das ein Copyright nicht lohnt. * * * * Verwendung * * -- Bereitstellen eines Streams, z.B. TFileStream * * * * csvReader := TCSVReader.Create (CSVDAtaStream, ';'); * * While not csvReader.Eof Do Begin * * For i:=0 to csvReader.ColumnCount - 1 Do * * Memo.Lines.Add (csvReader.Columns[i]); * * csvReader.Next; * * End; * ******************************************************************************) Interface Uses System.Classes, System.SysUtils; Type TStringPos = Record spFirst: PChar; spLen: Integer; End; TCSVReader = Class private fBuffer, fPos, fEnd: PChar; fSize: Integer; fStream: TStream; fQuote, fDelimiter: Char; fAtEOF, fIsEOF: Boolean; fColumns: Array Of TStringPos; fColumnCount: Integer; fEOLChar: Char; fEOLLength: Integer; Function GetColumnByIndex(Index: Integer): String; Procedure SetEOLChar(Const Value: Char); Procedure Initialize; public // Wenn kein Delimiter angegeben wird, wird das Listentrennzeichen aus den // internationalen Einstellungen von Windows verwendet. Constructor Create(aStream: TStream; aDelimiter: Char = #0); Destructor Destroy; override; // Bewegt den internen Positionszeiger auf die erste Zeile der Datei Procedure First; // Bewegt den internen Positionszeiger auf die nächste Zeile der Datei Procedure Next; // Liefert TRUE, wenn keine Daten mehr abgerufen werden können. Function Eof: Boolean; // Liefert oder setzt das Trennzeichen Property Delimiter: Char read fDelimiter write fDelimiter; // Liefert oder setzt das Quote-Zeichen Property Quote: Char read fQuote write fQuote; // Liefert oder setzt das EOL-Zeichen (Windows #13, UNIX #10) Property EOLChar: Char read fEOLChar write SetEOLChar; // Liefert oder setzt die Länge der EOL-Zeichen (Windows : 2 [CR+LF], UNIX: 1 [LF]) Property EOLLength: Integer read fEOLLength write fEOLLength; // Liefert die Anzahl der Elemente der aktuellen Zeile Property ColumnCount: Integer read fColumnCount; // Liefert die einzelnen Elemente der aktuellen Zeile Property Columns[Index: Integer]: String read GetColumnByIndex; default; End; Implementation { TCSVReader } Constructor TCSVReader.Create(aStream: TStream; aDelimiter: Char); Begin fStream := aStream; fSize := fStream.Size - fStream.Position + 2; fBuffer := GetMemory(fSize); fPos := fBuffer; aStream.Read(fBuffer^, fSize); fEOLChar := #13; fEOLLength := 2; fBuffer[fSize - 2] := fEOLChar; fBuffer[fSize - 1] := #0; fEnd := fBuffer + fSize - 1; If aDelimiter = #0 Then fDelimiter := FormatSettings.ListSeparator Else fDelimiter := aDelimiter; fQuote := '"'; setLength(fColumns, 100); Initialize; End; Destructor TCSVReader.Destroy; Begin FreeMemory(fBuffer); Inherited; End; Function TCSVReader.Eof: Boolean; Begin Result := fIsEOF; End; Procedure TCSVReader.First; Begin Initialize; Next; End; Function TCSVReader.GetColumnByIndex(Index: Integer): String; Var p: PChar; i, l: Integer; Begin With fColumns[Index] Do If spLen = 0 Then Result := '' Else If spFirst^ = fQuote Then Begin setLength(Result, spLen - 2); p := spFirst + 1; l := spLen - 2; For i := 1 To spLen - 2 Do Begin Result[i] := p^; If (p^ = fQuote) And (p[1] = fQuote) Then Begin dec(l); inc(p, 2) End Else inc(p); End; SetLength(Result, l); End Else SetString(Result, spFirst, spLen); End; Procedure TCSVReader.Initialize; Begin fPos := fBuffer; fIsEOF := False; fAtEOF := False; fColumnCount := 0; End; Procedure TCSVReader.Next; Var p: PChar; pPrev: PChar; Procedure _GetString; Begin Repeat inc(p); If p^ = fQuote Then If p[1] = fQuote Then inc(p) Else break; Until False; inc(p); End; Begin pPrev := fPos; p := fPos; fColumnCount := 0; If fAtEOF Then If Eof Then Raise exception.Create('Try to read past eof') Else Begin fIsEOF := True; Exit; End; If p^ = fQuote Then _GetString; While p^ <> fEOLChar Do Begin If p^ = fDelimiter Then Begin If fColumnCount = Length(fColumns) Then SetLength(fColumns, 2 * Length(fColumns)); fColumns[fColumnCount].spFirst := pPrev; fColumns[fColumnCount].spLen := p - pPrev; inc(fColumnCount); inc(p); pPrev := p; If p^ = fQuote Then _GetString; End Else inc(p); End; If p <> fPos Then Begin If fColumnCount = Length(fColumns) Then SetLength(fColumns, Length(fColumns) + 1); fColumns[fColumnCount].spFirst := pPrev; fColumns[fColumnCount].spLen := p - pPrev; inc(fColumnCount); End; fPos := p; If (fPos[1] = #0) Then fAtEOF := True Else inc(fPos, fEOLLength); End; Procedure TCSVReader.SetEOLChar(Const Value: Char); Begin If fEOLChar <> Value Then Begin fEOLChar := Value; fBuffer[fSize - 2] := fEOLChar; End; End; End. |
AW: CSV Dateien einlesen
Zitat:
|
AW: CSV Dateien einlesen
Das müsste ich mir mal ganz in Ruhe anschauen. Wenn es schnell gehen soll, ersetze doch testhalber mal alle PChar durch PAnsiChar und alle Char durch AnsiChar. Funktioniert es dann?
|
AW: CSV Dateien einlesen
Zitat:
Gruß K-H |
AW: CSV Dateien einlesen
Stimmt, die habe ich überlesen.
|
AW: CSV Dateien einlesen
Zitat:
(logisch) fDelimiter := FormatSettings.ListSeparator (AnsiChar, Char) ...der .Listseparator ist ein (Char) muss doch einiges umgeschrieben werden. Ziehe mir gerade die Hilfe von E-XE3 heran. Ein Auszug sagt: Aufrufe von Read/ReadBuffer-Methoden von TStream Überprüfen Sie die Aufrufe von TStream.Read/ReadBuffer, wenn Strings oder Zeichen-Arrays verwendet werden. Sehen Sie sich das folgende Beispiel an: var S: string; L: Integer; Stream: TStream; Temp: AnsiString; begin // Vorhandener Code ist falsch, wenn String UnicodeString ist Stream.Read(L, SizeOf(Integer)); SetLength(S, L); Stream.Read(Pointer(S)^, L); // Richtig für Unicode-String-Daten Stream.Read(L, SizeOf(Integer)); SetLength(S, L); Stream.Read(Pointer(S)^, L * SizeOf(Char)); // <<-- Geben Sie die Puffergröße in Byte an // Richtig für Ansi-String-Daten Stream.Read(L, SizeOf(Integer)); SetLength(Temp, L); // <<-- Temporären AnsiString verwenden Stream.Read(Pointer(Temp)^, L * SizeOf(AnsiChar)); // <<-- Geben Sie die Puffergröße in Byte an S := Temp; // <<-- String auf Unicode erweitern end; |
AW: CSV Dateien einlesen
Zitat:
Der Listseperator ist ein Char was soll dann das "(Ansichar, Char)"? Irgendwann später wirst Du auch die Daten einlesen, da muß der Puffer entsprechend angepasst werden (
Delphi-Quellcode:
) soweit ganz richtig, aber was haben diese beiden sachen miteinander zu tun?
sizeof(char)
Und was ist wenn Du CSV-Dateien mit 16 und 8 Bit-Zeichen hast? Gruß K-H |
AW: CSV Dateien einlesen
Zitat:
das der fDelimiter=AnsiChar, und Listseperator=Char ist. (Darstellung war verwirrend, einfach vergessen)... Da ein einfaches Umschreiben in diesem Falle nicht möglich ist... |
AW: CSV Dateien einlesen
Aber ein Cast sollte doch funktionieren:
Delphi-Quellcode:
var
c: Ansichar; d: char; begin c := 'A'; d := Char(c); |
AW: CSV Dateien einlesen
Zitat:
dafür eine Menge andere Fehler. Es musste eine schnelle Lösung her. Habe das Ganze jetzt so gelöst... Liest "nur" die selbst gebastelten CSV-File. Also "Text";daten;"Text";Text;Daten
Delphi-Quellcode:
uses function Read_CSV(SG: TStringGrid; Dateiname: String): Boolean; . . procedure T_Zutaten.FormShow(Sender: TObject); var t: string; begin t:='C:\DB\Zutaten.csv'; Read_CSV (StringGrid1,t); end. . . // CSV File Einlesen =========================================================== function Read_CSV (SG: TStringGrid; Dateiname: String): Boolean; var OutputFile: TextFile; sOutputName: string; l: integer; c: integer; x,y: integer; s,t: string; begin // Startwerte Reihe StringGrid y:=-1; sOutputname:=Dateiname; AssignFile(OutputFile, sOutputName); Reset(OutputFile); try while not Eoln(outputFile) do begin x:=0; y:=y+1; SG.RowCount:=y+1; ReadLn(OutputFile, t); l:=length(t); s:=''; for c := 1 to l do begin if t[c]<> ';' then if t[c]<> '"' then s:=s+t[c]; // Trennzeichen gefunden if t[c] = ';' then begin if length(s)=0 then s:=' '; SG.Cells[x,y]:=s; s:=''; x:=x+1; if y=0 then SG.ColCount:=x; end; // Zeilen Ende if c = l then begin if length(s)=0 then s:=' '; SG.Cells[x,y]:=s; s:=''; x:=x+1; if y=0 then SG.ColCount:=x; end; end; end; finally CloseFile(OutputFile); Result:=True; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:52 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