Autor Beitrag
spacemanspiff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 53
Erhaltene Danke: 1



BeitragVerfasst: 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
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mo 27.12.10 12:40 
Moin und :welcome: im Forum!

user profile iconspacemanspiff hat folgendes geschrieben Zum zitierten Posting springen:
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... :nixweiss: ;)

user profile iconspacemanspiff hat folgendes geschrieben Zum zitierten Posting springen:
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. :idea:

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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 53
Erhaltene Danke: 1



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Mo 27.12.10 14:08 
Wenn die Textdatei immer gleich aufgebaut ist, würde ich das in einen Record einlesen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  TRec = packed record
    XNummer   : string[14];    // = "GERÄTENUMMER: "
    DatNummer : string[4];     // = "7684"
    XMessung  : string[17];    // = "GERÄTEMESSUNG #: "
    DatMessung: string[9];     // = "1425     ";
    ...
  end;

Dann kannst Du das bequem per Filestream einlesen
ausblenden Delphi-Quelltext
1:
FileStream.Read(Rec, SizeOf(Rec));					

und die relevanten Daten einfach auslesen.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: 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 :autsch: :roll:) und in Textzeilen und Binäranteil zerlegt bereitstellt. Der entscheidende Teil ist das hier:
ausblenden volle Höhe Delphi-Quelltext
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[1in [#10,#13]) do begin
        Result := Result +Data[1];
        Delete(Data,1,1);
      end;
    while (Data <> ''and (Data[1in [#10,#13]) do
      Delete(Data,1,1);
  end;

begin
  FLines.Clear;
  FBinData := NIL;
  SetLength(Data, AStream.Size); // Platz machen
  if (AStream.Read(PAnsiChar(Data)^, Length(Data)) = Length(Data)) then begin // alle Daten geladen?
    while (Data <> ''do begin // bis alle Daten verarbeitet sind
      Line := CutLine;
      if (Line <> ''then begin // keine Leerzeilen
        if (Line = ':::DATA BEGIN:::'then begin // Text-Terminator, Rest binär?
          SetLength(FBinData, Length(Data)); // Platz machen
          System.Move(PAnsiChar(Data)^, FBinData[0], Length(Data)); // Daten kopieren
          Data := ''// alles verarbeitet
        end
        else // sonst Textzeile in die Liste
          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. :nixweiss:

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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 53
Erhaltene Danke: 1



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 53
Erhaltene Danke: 1



BeitragVerfasst: 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