Autor |
Beitrag |
spacemanspiff
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Mo 27.12.10 12:01
Hallo zusammen,
der Delphi-Neuling bräuchte mal wieder Lösungsansätze, da meine Forensuche nicht viel Verwertbares gebracht hat.
Ich habe an mein Programm eine Datenbank angebunden und möchte nun Textdateien mit Messdaten importieren können. Der User kann sich dazu einen Ordner auswählen und darin nach Textdateien suchen. Diese werden dann in einer ListBox gelistet und angezeigt.
Ein Textfile sieht ungefähr so aus
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| ... Messort: 00041015 Messdatum: 11.12.2010 Messbeginn: 11:25 Messende: 11:33 Messwert: 15,1 mg Messdaten: ...ab hier 1440 Byte-Werte... ... |
Ich habe mir dazu ein Record angelegt, dass den Einträgen der Datenbanktabelle entspricht. Jetzt suche ich nach einer cleveren Möglichkeit, das Textfile einzulesen und die relevanten Werte zu extrahieren. Im oberen Beispiel bräuchte ich also die Werte 00041015 als Integer, 11.12.2010 als Datum, 11:25 und 11:33 als Time, 15,1 als Float oder Double und dann die Bytes als Byte-Array. Eine weitere Schwierigkeit besteht darin, dass die Einträge keine absolute Position haben, da auch Werte darin sind, die eine unterschiedliche Zeichenlänge haben. Ziel sollte es aber sein, nach dem Einlesen, die korrekten Werte in dem Record stehen zu haben, so dass ich sie gleich in die DB übertragen kann und mit dem nächsten Textfile fortfahren kann.
Bin für Vorschläge offen und dankbar. Ich kann mir natürlich den Umweg über Stringcompares machen und mir die Integer und Dates usw mühsam zusammennasteln, aber ich denke, Delphi bietet bereits etliche gute Methoden solche Problemstellungen zu lösen. Mir sind sie nur nicht bekannt, da es mein erstes Delphi-Projekt ist.
Vielen Dank und liebe Grüße,
Thomas
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 27.12.10 12:40
Moin und  im Forum!
spacemanspiff hat folgendes geschrieben : | Ich kann mir natürlich den Umweg über Stringcompares machen und mir die Integer und Dates usw mühsam zusammennasteln, aber ich denke, Delphi bietet bereits etliche gute Methoden solche Problemstellungen zu lösen. Mir sind sie nur nicht bekannt, |
Hm, also mir sind solche ominösen eierlegenden Wollmilchsau-Methoden in Delphi auch unbekannt, die Textdateien, egal welches Format sie haben, einfach so "auslesen" können...
spacemanspiff hat folgendes geschrieben : | Ein Textfile sieht ungefähr so aus |
Es hängt sehr stark davon ab, wie diese Textdateien wirklich aufgebaut sind und wie groß die Varianz im Format ist/sein kann.
Man könnte mit regulären Ausdrücken da ran gehen, aber das ist relativ langsam, wenn es also um viele Dateien geht, ist das vermutlich sehr viel schneller, wenn du die Daten "selbst" extrahierst.
Mach doch mal einen Code-Vorschlag, den können wir dann verbessern oder häng mal eine Datei zum Test an, damit man mal "Echtfutter" zum testen hat.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
spacemanspiff 
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Mo 27.12.10 12:55
Hi Narses und danke für die Antwort,
momentan gehe ich mal mit einem TFileStream ran und versuche mir eine Token-Funktion zusammenzuschustern, der ich als Parameter den Delimiter übergebe. Was nämlich alle Files gemeinsam haben ist ein Doppelpunkt nach der Info (z.B. Messdatum:) und danach der relevante Wert gefolgt von CR und LF. Nur das Byte-Array muss in einem Stück gelesen werden, da es Binärdaten sind und da alle möglichen Zeichen drin stehen können. Aber das sind immer gleich viele Bytes und immer am Schluß der Datei. Die Reihenfolge ist auch immer die gleiche, also suche ich grad nach einer Möglichkeit die in etwa folgendes tut:
- File einlesen
- alles einschließlich Delimiter ':' und nachfolgendes Whitespace wegschmeissen
- alles bis zum CR/LF einlesen
- nachfolgende Whitespaces entfernen (manchmal als 'Füllmaterial' drin)
- je nach Datentyp darauf reagieren (String, Int, Date, etc.)
- weiter bis die Binärdaten anfangen, diese dann einlesen
- in DB schreiben
- falls noch Items vorhanden wieder oben anfangen
Ich habe Dir mal eine Textdatei angehängt. Die Positionen der Werte wird sich schätzungsweise um 5-10 Byte verändern können.
Da ich ja noch neu im Delphiland bin, kannst Du mir vielleicht Tipps geben, mit welchen Objekten sich oben beschriebene Prozedur umsetzen lässt? Vielleicht eignet sich ja das TFileStream-Objekt schon gar nicht. Bin noch am testen und brauche auch entsprechend lang.
Danke und Gruß,
Thomas
Einloggen, um Attachments anzusehen!
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Mo 27.12.10 14:08
Wenn die Textdatei immer gleich aufgebaut ist, würde ich das in einen Record einlesen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| type TRec = packed record XNummer : string[14]; DatNummer : string[4]; XMessung : string[17]; DatMessung: string[9]; ... end; |
Dann kannst Du das bequem per Filestream einlesen
Delphi-Quelltext 1:
| FileStream.Read(Rec, SizeOf(Rec)); |
und die relevanten Daten einfach auslesen.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 27.12.10 14:09
Moin!
Weil ja gerade Weihnachten war habe ich dir mal ein Demo-Projekt angehangen, dass eine Klasse enthält, die zumindest eine Textdatei einlesen kann (wer hat sich das eigentlich mit den Binärdaten in einer Textdatei ausgedacht  ) und in Textzeilen und Binäranteil zerlegt bereitstellt. Der entscheidende Teil ist das hier:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| type TByteArray = array of Byte;
TSensorReading = class(TOBject) private FLines: TStringList; FBinData: TByteArray; public constructor Create; destructor Destroy; override; property Lines: TStringList read FLines; property BinData: TByteArray read FBinData; procedure ReadFromStream(AStream: TStream); procedure ReadFromFile(const AFilename: String); end;
implementation
procedure TSensorReading.ReadFromStream(AStream: TStream); var Data, Line: AnsiString;
function CutLine: AnsiString; begin Result := ''; while (Data <> '') and NOT (Data[1] in [#10,#13]) do begin Result := Result +Data[1]; Delete(Data,1,1); end; while (Data <> '') and (Data[1] in [#10,#13]) do Delete(Data,1,1); end;
begin FLines.Clear; FBinData := NIL; SetLength(Data, AStream.Size); if (AStream.Read(PAnsiChar(Data)^, Length(Data)) = Length(Data)) then begin while (Data <> '') do begin Line := CutLine; if (Line <> '') then begin if (Line = ':::DATA BEGIN:::') then begin SetLength(FBinData, Length(Data)); System.Move(PAnsiChar(Data)^, FBinData[0], Length(Data)); Data := ''; end else FLines.Add(Line); end; end; end else raise Exception.Create('Fehler beim Lesen der Daten!'); end; | Das ist jetzt nicht die performanteste/speichersparendste Lösung, da ich bei den Stringoperationen die einfachsten und daher selbsterklärenden Funktionen verwendet habe (man sollte bei Strings besser nicht mit Einzelzeichen hantieren). Da die Dateien aber relativ klein sind, sollte das keinen soo schlimmen Effekt haben. Weiterhin: wenn du mit einer Delphi-Version >=D2k9 arbeitest könnte es vielleicht Probleme mit Unicode geben, da habe ich jetzt nicht so sehr drauf geachtet.
cu
Narses
Einloggen, um Attachments anzusehen!
_________________ There are 10 types of people - those who understand binary and those who don´t.
Für diesen Beitrag haben gedankt: spacemanspiff
|
|
spacemanspiff 
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Mo 27.12.10 14:37
@Gerd,
leider klappt eine solch angenehme Lösung nicht, da die absoluten Positionen sich ändern können
@Nardes
vielen Dank für die Mühe. Ich schaue gleich mal in Ruhe drüber, was Du da genau machst
Die Binärdaten sind im Textfile, weil die von einem kleinen Microcontroller stammen, der froh ist, dass er überhaupt ein Dateisystem verwalten kann. Wie hättest Du das denn gemacht? (für's nächste mal, vielleicht können wir es ja implementieren).
Und ja, ich habe eine neuere Delphi-Version (2010 professional) und Probleme mit Unicode. Sieht alles ein wenig chinesisch aus, was er da einliest. Muss scheinbar noch einen Umweg nehmen, denn ganze Zeilen als Strings einlesen will nicht so recht klappern.
Wie gesagt: Vielen Dank, ich schaue mir Deinen Code jetzt mal in Ruhe an.
Thomas
EDIT:
Also das sieht doch echt ganz hübsch aus, das werde ich so übernehmen. Für's nächste Mal (das sicherlich folgen wird) brauchst mir aber keinen Code hinpinnen, da lernt man so wenig bei  (Soll nicht heissen, dass ich nicht dankbar bin!) Das Unicode-Problem kann man glaube ich umgehen, wenn man beim einlesen noch Chr() benutzt.
|
|
spacemanspiff 
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Mo 27.12.10 17:04
So...
ich habe Deine Lösung mal im Groben übernommen Narses. An den einzelnen Lines habe ich mich dann doch "zu Fuss" entlang gehangelt, um die Werte zu extrahieren. Jetzt habe ich gleich das nächste Problem, weil ich das erste Mal BLOB's mit Inhalten füllen und abspeichern will. Aber ich denke, das bekomme ich noch hin. Danke vielmals und bis zum nächsten Mal
Beste Grüße,
Thomas
|
|
|