Autor Beitrag
andariel
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 21.03.08 16:26 
Aloha,

ich bin ja hier noch ganz frisch und konnte meine Antworten bisher immer schon in anderen Threads finden, aber hier komme ich allein durch suchen nicht weiter ^^

Ich muss Daten aus einer Logdatei in ein Memory Table reinlesen. Da in so einer Logdatei durchaus recht viel stehen kann (500.000 Datensätze), dauert es doch leider recht lange, wenn ich das im Hauptthread einer Anwendung mache.

Das Problem ist, dass dabei auch die GUI entsprechend langsam gezeichnet wird... und und und :) quasi alles, was mit so langwierigen Prozessen zusammenhängt.

Nun überlegte ich mir, ob es nicht sinnvoll wäre, das Einlesen der Daten in einen Thread auszulagern. Ich habe bislang nur kaum Erfahrungen mit Threads gemacht...

kann mir vielleicht jemand auf die Sprünge helfen, wie ich die folgende Funktion in einem Thread umsetzen kann?

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:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
function TMainForm.ParseFile(const aFileName : String) : Boolean;
var
  loc_file    : File;

  loc_start,
  loc_pos,
  loc_size    : Integer;

  loc_type,
  loc_line    : String;
  loc_text    : PChar;
  loc_list    : TStringList;
begin
  Result := False;

  if FileExists(aFileName) then begin
    // Abhängig von Aufrufparametern wird nicht das MainForm, sondern nur eine Art
    // SplashScreen angezeigt, auf dem die einzelnen Arbeitsschritte angezeigt werden
    DisplayCurrentJob('Generating DataSet');

    // Die Logdateien unserer Anwendungen sind teils unterschiedlich aufgebaut,
    // dadurch muss nun ermittelt werden, welches Format dieses hat
    loc_type := GetFileType(aFileName);
    if (loc_type = EmptyStr) then begin
      MessageDlg('Invalid file!', mtError, [mbOk], 0);
      Exit;
    end;

    // Die Struktur des MemoryTables muss an den Typ der Logdatei angepasst werden
    GetRecordLayOut(loc_type);
    SetLogDataTableLayout(loc_type + '.Length');
    FFileName := aFileName;

    AssignFile(loc_file, FFileName);
    Reset(loc_file, 1);
    loc_size := FileSize(loc_file);

    // FProgress kapselt den Zugriff auf die verwendete Progressbar, je nachdem ob
    // das SplashFenster oder das MainForm angezeigt wird.
    FProgress.Max := loc_size;

{$WARN UNSAFE_CODE OFF}
    GetMem(loc_text, Succ(loc_size));
    try
      BlockRead(loc_file, loc_text^, loc_size);
      CloseFile(loc_file);

      loc_line  := EmptyStr;
      loc_pos   := 0;
      loc_start := 0;

      loc_list := TStringList.Create;
      try
        while not (loc_text[loc_start + loc_pos] = #0) do begin

          loc_pos := 0;
          loc_line := EmptyStr;
          while not (loc_text[loc_start + loc_pos] in [#13, #10, #0]) do
            inc(loc_pos);

          if (loc_text[loc_start + loc_pos] in [#13, #10]) then begin
            loc_text[loc_start + loc_pos] := #0;
            loc_line := StrPas(@loc_text[loc_start]);

            // SplitLine trennt die verschiedenen Werte in einer Zeile der Logdatei
            // auf, so dass diese in einer StringList landen und in das MemoryTable
            // geschrieben werden können
            SplitLine(loc_line, Char(','), Char('"'), True, loc_list);
            // Auf Basis der geloggten Werte sollen nachher die Datensätze auch 
            // gefiltert werden können (z.B. IP- Adresse, MAC- Adresse, Username, ...)
            AddFilterOptions(loc_list);
            // Der Datensatz muss natürlich auch noch weggeschrieben werden
            AddRecord(tblLogData, loc_list);

            { Set offset to line start }
            loc_text[loc_start + loc_pos] := #13;
            loc_start := loc_start + loc_pos + 2;
          end;

          FProgress.Pos := loc_start;
        end;
        DisplayCurrentJob(
                          Format(
                                 'File "%s" has been processed',
                                 [ExtractFileName(aFileName)]
                                ),
                          False
                         );
        DisplayCurrentJob('DataSet generated');
      finally
        loc_list.Clear;
        FreeAndNil(loc_list);
      end;
    finally
      FreeMemory(loc_text);
    end;
{$WARN UNSAFE_CODE ON}

    FProgress.Pos := FProgress.Max;
    Application.ProcessMessages;
    Result := True;
  end;
end;


Braucht Ihr noch andere Funktionen aus dem Projekt? Wie soll ich das am besten aufsplitten?

Vielen Dank

Andariel
andariel
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 25.03.08 15:33 
kann mir hier wirklich niemand helfen? :cry:
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Di 25.03.08 22:10 
user profile iconandariel hat folgendes geschrieben:
kann mir hier wirklich niemand helfen? :cry:


Im Prinzip musst Du nur die Zugriffe auf die VCL (Fortschrittsanzeige bzw. Fehlermeldungen) anders loesen, ansonsten muesste der Code so, wie er ist, in einem Hintergrundthread funktionieren. Allerdings habe ich gerade nur kurz druebergelesen und moeglicherweise ein paar Fallstricke uebersehen.

twm