Avatar billede michdan Nybegynder
31. maj 2005 - 15:48 Der er 17 kommentarer og
1 løsning

Søge efter tekst i store filer

Jeg vil gerne lave et værktøj til at analysere logfiler med, som er rene tekstfiler 10 mb store.

Værktøjet skal kunne gennemsøge alle filer i et directory og finde alle forkomster af søgeordet fra alle filer. Når søgeordet er fundet skal linjen hvor det forekommer kopieres og vises i f.eks en memo felt.

Mime spm:
1) Hvordan søger man mest effektivt i tekstfiler ?

2) Er det en fordel at kopiere filen ind i f.eks. en stringlist, stringgrid eller lignende ?

3) Hvordan får jeg kopieret den fundne linje over i memofelt ?
4) Er der nogen der har prøvet noget ligende og evt har et eksempel på dette ?

mvh
michael
Avatar billede kroning Nybegynder
31. maj 2005 - 16:37 #1
Dette er vel den simple måde men det er nok ikke den hurtigeste, på min langsomme maskine (1.2 Ghz AMD pipfugl) tager det ca. 1 sekund at indlæse en 11 MB textfil og søge gennem den. Hvis opdateringen af button1 aktiveres tager det BETYDELIG længere tid.

Smid en Memo1 på en form.

procedure TForm1.FindTekst(Tekst : string);
var
  StringList : TStringList;
  i : integer;
begin
  StringList:=TStringList.Create;
  StringList.LoadFromFile('c:\hk\manual.txt'); // en 11MB fil
  for i:=0 to StringList.Count-1 do
  begin
    if Pos(Tekst,StringList[i])>0 then
      Memo1.Lines.Add(StringList[i]);
//  Button1.Caption:=IntTostr(i);
//  Button1.Update;
  end;

  StringList.Free;
end;
Avatar billede michdan Nybegynder
31. maj 2005 - 18:15 #2
hej kroning

Det var lettere end jeg havde håbet på....:-)

Som sagt vil jeg gerne lave et værktøj til at analysere log filer med, så det skal kunne søge igennem flere filer og sortere resultatet efter f.eks. tidsstempel.

Vil brug af stringlist og en memo stadig være det bedste valg ??
Kunne det tænkes at der skal bruges threads for at optimere søgningen ??

mvh
michael
Avatar billede kroning Nybegynder
31. maj 2005 - 19:01 #3
Jeg skal ikke kunne sige om stringlist og memo er det bedste valg, jeg tror det ikke men det er det eneste jeg lige kan komme på. Hvis de fundne data skal præsenteres for brugeren så er en ListView måske bedre, hvis de ikke skal præsenteres for brugeren så er der ingen grund til at bruge en memo eller ListView så ville jeg bruge en StringList til også at gemme resultatet i.
Mht. thread så tror jeg ikke at du vil få noget ud af at bruge flere threads, en enkelt ville nok være en god ide for at undgå at hoved formen dør mens der søges.
Nu ser jeg lige at du skriver " sortere resultatet efter f.eks. tidsstempel.
" så ville jeg nok bruge en ListView hvis brugeren skal se resultatet eller en StringList hvis ikke.
Avatar billede michdan Nybegynder
31. maj 2005 - 19:29 #4
ok takker for svarene....hvis du vil have points skal du vist lave et svar istedet for en kommentar....
Avatar billede kroning Nybegynder
31. maj 2005 - 19:50 #5
ok
Avatar billede kroning Nybegynder
31. maj 2005 - 19:52 #6
Jeg mener ok hvis der ikke er andre der har bedre ideer, hvis du venter lidt med at godkende svar så kommer der måske flere/bedre forslag.
Avatar billede michdan Nybegynder
31. maj 2005 - 19:55 #7
hej kroning

der dukkede alligevel lige et spm mere op....

Hvis man skal bruge en listview til at vise resultat og filen læses ind i en strinlist først, hvordan får jeg så de enkelte dele fra stringlisten ind i de respektive kolonner i listviewen ???

en linie fra loggen ser f.eks. sådan ud:
21:32:11.593,D,PC:2032,server.cpp:1222, ID=27621098 Destination=16 operation=1

Den består af disse 5 dele adskilt med komma:
<tidsstempel>,<kategori>,<thread>,<filenavn:linje>,<log tekst>

Har du nogen ide om hvordan jeg kunne få dette lagt ind i 5 kolonner i listviewen ??

mvh
michael
Avatar billede kroning Nybegynder
31. maj 2005 - 20:36 #8
Hvis din ListView hedder ListView1 og har 5 kolonner:

procedure TForm1.FindTekst(Tekst : string);
var
  StringList,LinieList : TStringList;
  i : integer;

procedure SendToListView;
var
  i : integer;
begin
  LinieList.Clear;
  ExtractStrings([','],[],PChar(StringList[i]),LinieList);
  if LinieList.Count=5 then
  begin
    with ListView1.Items.Add do
    begin
      Caption:=LinieList[0];
      for i:=1 to 4 do
          SubItems.Add(LinieList[i]);
    end;
  end
  else
  showmessage('FEJL: Der er ikke 5 kolonner')
end;

begin
  LinieList:=TStringList.Create;
  StringList:=TStringList.Create;
  StringList.LoadFromFile('c:\hk\manual.txt'); // en 11MB fil
  for i:=0 to StringList.Count-1 do
  begin
    if Pos(Tekst,StringList[i])>0 then
        SendToListView;
  end;

  StringList.Free;
  LinieList.Free;
end;

ok, jeg skal til at læse hvad du skriver inden jeg går igang, jeg kan se at du gerne ville have resultatet ind i en stringlist først, er det nødvedigt for så kan jeg lige rette den til?
Avatar billede michdan Nybegynder
31. maj 2005 - 20:57 #9
hej kroning

Nej ikke nødvendigvis...det var bare dit første forslag jeg tog udgangspunkt i...

jeg har lige afprøvet det og det virker ok.....respekt du har fod på det delphi programmering må jeg sige...:-)

Du får alle points..

mvh
michael
Avatar billede kroning Nybegynder
01. juni 2005 - 13:26 #10
Der en en fejl i proceduren kom jeg lige i tanke om, den lokale variable i: i SendToListView skal rettes til f.eks. x og:

for i:=1 to 4 do
  SubItems.Add(LinieList[i]);

skal så self. rettes til:

for x:=1 to 4 do
  SubItems.Add(LinieList[x]);
Avatar billede michdan Nybegynder
01. juni 2005 - 14:00 #11
takker...

Jeg har også fundet ud af at der er flere af mine logfiler hvor der forekommer ',' tegn i selve log teksten og det gør at funktionen 'ExtractStrings' finder flere forekomster i stringlisten end 5. (LinieList.Count > 5)

Kender du en anden metode til at gennemsøge sådan en stringlist, så jeg kun bruger de første 4 fundne og de resterende samles i den 5 LinieList[5] ??

mvh
michael
Avatar billede kroning Nybegynder
01. juni 2005 - 14:17 #12
Hvis du skifter SendToListView ud med denne burde det virke, hvis din log tekst ikke altid starter med ID= så vil det ikke virke, så skriv igen.

procedure SendToListView;
var
  x : integer;
begin
  LinieList.Clear;
  ExtractStrings([','],[],PChar(StringList[i]),LinieList);
  if LinieList.Count>4 then
  begin
    with ListView1.Items.Add do
    begin
      Caption:=LinieList[0];
      for x:=1 to 3 do
          SubItems.Add(LinieList[x]);
      SubItems.Add(copy(StringList[i],Pos('ID=',StringList[i]),MaxInt));
    end;
  end
  else
    showmessage('FEJL: Der er mindre end 5 kolonner')
end;
Avatar billede kroning Nybegynder
01. juni 2005 - 14:22 #13
Du kunne også bare gøre sådan, så er det ligemeget om din log tekst starter med ID=

procedure SendToListView;
var
  x : integer;
begin
  LinieList.Clear;
  ExtractStrings([','],[],PChar(StringList[i]),LinieList);
  if LinieList.Count>4 then
  begin
    with ListView1.Items.Add do
    begin
      Caption:=LinieList[0];
      for x:=1 to 4 do
          SubItems.Add(LinieList[x]);
      for x:=5 to LinieList.Count-1 do
    SubItems[3]:=SubItems[3]+','+LinieList[x];
    end;
  end
  else
    showmessage('FEJL: Der er mindre end 5 kolonner')
end;
Avatar billede michdan Nybegynder
01. juni 2005 - 15:43 #14
nej logteksten starter ikke med noget bestemt, men kan være hvad som helst, derfor var der også også pludselig nogen med komma-tegn i teksten.
Det skyldes at loggen bruges af mange forskellige applikationer på samme tid.

Men jeg vil prøve det du postede....

mvh
michael
Avatar billede kroning Nybegynder
01. juni 2005 - 17:11 #15
Hvis de 4 første dele i dine log linier altid har samme længde kunne man også benytte nogle copy(a,b) i stedet for ExtractStrings, det ville nok være hurtigere men hvis det kun drejer sig om nogle få linier der findes ved søgninger så er det self. ligemeget.
Avatar billede michdan Nybegynder
01. juni 2005 - 17:31 #16
jo men en copy(a,b) skal vel stadig først have opdelt den fundne linje i de 5 delelementer og det er jo det funktionen ExtractStrings gør !???

eller findes der en funktion til kopiering som også kan finde seperator tegn som ',' ??
Avatar billede kroning Nybegynder
01. juni 2005 - 18:12 #17
Jeg tænkte på at hvis:
21:32:11.593,D,PC:2032,server.cpp:1222, ID=27621098 Destination=16 operation=1
<tidsstempel>,<kategori>,<thread>,<filenavn:linje>,<log tekst>

Tidsstempel altid var fra 1 til 12
kategori altid fra 14 til 15
thread altid fra 16 til 23
osv.
så ville en copy(a,b) for hver del nok være hurtigere end at bruge ExtractStrings.
Avatar billede michdan Nybegynder
01. juni 2005 - 21:08 #18
ja ok det kan jeg godt se....men ville så være meget låst af dette...jeg tror også den første version er hurtig nok....men jeg vil prøve med flere søgninger i flere filer...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester