Autor |
Beitrag |
Tobi482
Beiträge: 135
|
Verfasst: So 05.10.08 11:40
hi Leute,
heute hat es Delphi wieder einmal geschafft mich total zuverwirren. Es scheint, als ob Schleifendruchgänge des Schleifenkörpers einfach nicht ausgeführt werden.
Ich möchte eine Datei nach speziellen Squenzen von Zeichen durchsuchen. Daher lese ich die ganze Datei in einen Buffer ein und kontrolliere jedes Zeichen, ob es der Anfang einer gesuchten Sequenz ist.
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:
| procedure Tmain.btn_scanClick(Sender: TObject); var pData : Pointer; hFile : Integer; Size : Cardinal; i,j : Cardinal; begin if not od.Execute then exit;
hFile := FileOpen(od.FileName, fmOpenReadWrite); if hFile = -1 then begin Addlog('Fehler beim öffnen der Datei'); Exit; end;
Size := GetFileSizeEx(od.FileName);
pData := GetMemory(Size);
FileRead(hFile, pData^, Size);
j := 0; for i := 0 to Size-255-1 do begin if isSequenceOffset(Ptr(Cardinal(pData)+i)) then begin j := j + 1; Addlog('Sequenz gefunden bei ' + IntToHex(i, 8)); end;
if i mod 1000 = 0 then begin main.Caption := FloatToStr(i/size*100); end; end; Addlog(IntToStr(j) + ' Sequenzen gefunden');
FileClose(hFile);
FreeMemory(pData); end; |
Einige Dateien sind sehr groß, und das suchen dauert sehr lange. Daher habe ich einen Prozentanzeige in den Fensternnamen gepackt. Würde ich diese Anzeige bei jedem Durchlauf refreshen ist dies eine große Performance-Bremse. Daher lasse ich die Caption nur alle 1000 Schleifendruchläufe aktualisieren.
Soweit sogut^^
Zur Probe habe ich eine Datei mit 1000 der gesuchten Squenzen erzeugt. Davon werden jedoch nur 16 gefunden.
JETZT KOMMT DER HAMMER.
Stelle ich die mod-Zeile "if i mod 1000 = 0 then" auf "if i mod 500 = 0 then" werden 233 gefunden. Mit "if i mod 100 = 0 then" werden 532 gefunden und bei "mod 1" alle.
BITTE WAS?
WIE WO WAS WARUM?
Wie kann diese Zeile den Ablauf derart beeinflussen?
Mit freundlichen Grüßen
Tobi
|
|
GTA-Place
Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: So 05.10.08 11:54
Ruf Application.ProcessMessages; auf, bevor du die Daten in ein Log einträgst.
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
Tobi482
Beiträge: 135
|
Verfasst: So 05.10.08 11:59
Wenn die Zeilen nicht angezeigt werden sollten, dann müsste doch aber die Anzahl in j stimmen.
Leider funktioniert auch diese Code "nicht". Wenn man mod verändert werden jeweils mehr Sequenzen gefunden.
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:
| procedure Tmain.btn_scanClick(Sender: TObject); var pData : Pointer; hFile : Integer; Size : Cardinal; i,j : Cardinal; begin if not od.Execute then exit; Application.ProcessMessages;
hFile := FileOpen(od.FileName, fmOpenReadWrite); Application.ProcessMessages; if hFile = -1 then begin Addlog('Fehler beim öffnen der Datei'); Exit; end;
Size := GetFileSizeEx(od.FileName); Application.ProcessMessages;
pData := GetMemory(Size); Application.ProcessMessages;
FileRead(hFile, pData^, Size); Application.ProcessMessages;
j := 0; for i := 0 to Size-255-1 do begin if isSequenceOffset(Ptr(Cardinal(pData)+i)) then begin Application.ProcessMessages; j := j + 1; Application.ProcessMessages; Addlog('Sequenz gefunden bei ' + IntToHex(i, 8)); Application.ProcessMessages end; Application.ProcessMessages;
if i mod 1000 = 0 then begin main.Caption := FloatToStr(i/size*100); Application.ProcessMessages; end; Application.ProcessMessages;
end; Addlog(IntToStr(j) + ' Sequenzen gefunden'); Application.ProcessMessages;
FileClose(hFile); Application.ProcessMessages;
FreeMemory(pData); Application.ProcessMessages; end; |
Gruß Tobi
|
|
Hidden
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: So 05.10.08 12:18
Hi,
Du kannst dein Suchfenster aber meißtens um mehr als eins verschieben Da lässt sich noch sehr viel optimieren.
Aber warum verwendest du nicht einfach die vordefinierte Funktion "Pos"? Die ist wahrscheinlich um das zig-fache schneller und du brauchst deine ProgressBar vielleicht garnicht.
Delphi-Quelltext 1:
| function Pos(const Keyword, S: String): Integer; |
Wenn der Teilstring nicht enthalten ist, ist der Rückgabewert null.
mfG,
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 12:26
Hidden hat folgendes geschrieben : | Aber warum verwendest du nicht einfach die vordefinierte Funktion "Pos"? Die ist wahrscheinlich um das zig-fache schneller und du brauchst deine ProgressBar vielleicht garnicht. |
Das dürfte bei sehr großen Dateien trotzdem lange dauern. // EDIT: --> Wie wäre es mit Threads? Oder was Hidden vermutlich auch meinte: Boyer-Moore?
Tobi482 hat folgendes geschrieben : | Wie kann diese Zeile den Ablauf derart beeinflussen? |
Bei solchen "unerklärlichen" Fehlern würde ich mal vermuten, dass du da irgendwo auf falsche Speicherbereiche zugreifst bzw. diese überschreibst, was dann solche Effekte hat. (Ich habs mir jetzt nicht genauer angeschaut.)
|
|
Tobi482
Beiträge: 135
|
Verfasst: So 05.10.08 12:32
Pos funktioniert nur, wenn die Sequenze durch reguläre ausdrücke darstellbar ist. Mein ausdruck wäre aber sehr sehr lang (reg exp = 255 verschieden Zeichen hintereinander). aber ich habe noch was cooles herrausgefunden
Dieser Code findet alles Squenzen
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| j := 0; for i := 0 to Size-255-1 do begin
if isSequnceOffset(Ptr(Cardinal(pData)+i)) then begin j := j + 1; Addlog('Sequenz gefunden bei ' + IntToHex(i, 8)); end;
main.Caption := 'a'; end; Addlog(IntToStr(j) + ' Sequenzen gefunden'); |
Dieser Code findet keine Squenz
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| j := 0; for i := 0 to Size-255-1 do begin
if isSequnceOffset(Ptr(Cardinal(pData)+i)) then begin j := j + 1; Addlog('Sequenz gefunden bei ' + IntToHex(i, 8)); end;
end; Addlog(IntToStr(j) + ' Sequenzen gefunden'); |
Nun bin ihc völlig verwirrt, was zum Teufel hat meine Frame main damit am hut?
Gruß
Tobi
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 12:34
Wie gesagt: Du überschreibst irgendwo den falschen Speicher, das muss nicht an dieser Stelle passieren, sondern irgendwo im Code. Typisch dafür ist, dass die Effekte beim Zugriff auf VCL-Komponenten passieren, denn die reagieren eben allergisch darauf.
|
|
Tobi482
Beiträge: 135
|
Verfasst: So 05.10.08 12:38
Code funktioniert nicht
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| AssignFile(f, '.\c.ini'); Rewrite(f);
j := 0; for i := 0 to Size-255-1 do begin
if isSequenceOffset(Ptr(Cardinal(pData)+i)) then begin j := j + 1; Addlog('Sequenz gefunden bei ' + IntToHex(i, 8)); end;
end; Addlog(IntToStr(j) + ' Sequenzen gefunden');
closefile(f); |
Code funktioniert
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| AssignFile(f, '.\c.ini'); Rewrite(f);
j := 0; for i := 0 to Size-255-1 do begin
if isSequenceOffset(Ptr(Cardinal(pData)+i)) then begin j := j + 1; Addlog('Sequenz gefunden bei ' + IntToHex(i, 8)); end;
Writeln(f, inttostr(i)); end; Addlog(IntToStr(j) + ' Sequenzen gefunden');
closefile(f); |
AHHH DELPHI IST VERRÜCKT !!!
ok wenn das so ist, wie du sagt, dass ich das irgendwas überschrieben wie umgehe ich dass, ohne "schrott" in meine funktion zu bauen?
Gruß
Tobi
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 12:39
Den Fehler finden .
Wobei ich jetzt deinen aktuellen Code nicht genauer nach Fehlern angeschaut habe.
|
|
Hidden
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: So 05.10.08 13:05
Hi,
Wäre schön, wenn du bei Vergleichen immer kurz die Unterschiede auch highlighten könntest
Ja, Ich meinte Boyer-Moore Wusste nur nichtmehr, wie's heißt und dachte damit muss er sich ja nicht unbedingt beschäftigen -> ist doch afaik in Pos() drin?
Naja, egal. Wenn irgendwo Speicherüberschreitungen sind, hat das erstmal Vorrang vor Optimierungen.
mfG,
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 13:06
Nein, Pos arbeitet sequentiell, deshalb hatte ich BM mal selbst als Pos-Ersatz umgesetzt, besonders viel schneller war das meistens aber auch nicht, es lohnt sich eben nicht immer.
|
|
Tobi482
Beiträge: 135
|
Verfasst: So 05.10.08 13:15
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 13:18
Hast du es mal getestet, wenn nur dieser Code in einem neuen Projekt steckt? Kannst du ein Beispielprojekt anhängen? Dann würde ich mir das mal anschauen, gerade, wenn da irgendwo Speicher überschrieben wird, ist das nicht so einfach so zu sehen, was auch daran liegt, dass isSequenceOffset ja vermutlich eine eigene Funktion ist, oder? (Mal abgesehen davon, dass der Fehler vermutlich gar nicht im geposteten Quelltext steckt.)
|
|
Ginger
Hält's aus hier
Beiträge: 2
|
Verfasst: So 05.10.08 13:23
So wie es aussieht funktioniert der Code immer dann wenn in der Schleife ein String angefasst wird.
Wird der Form-Titel geängert, gehts, Ausgabe eines String in eine Datei -> es geht.
Völlig irrelevante Stringoperation + 'a' und es funktioniert.
Ergibt das Sinn?
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 13:26
Ja, weil es eben vollkommen egal sein kann was du änderst, wenn du einen Fehler mit überschriebene Speicher hast, sondern das Entscheidende ist, dass du etwas änderst.
// EDIT:
Stell dir das so vor:
Du hast zwei Geschäfte nebeneinander, jetzt breitest du deine Warenauslage (Speicherbereich) bis zu deinem Nachbarn (andere Variable) aus und greifst auf dessen Warenauslage zu (das was in der anderen Variable liegt).
Dabei nimmst du beispielsweise eine Melone aus seiner Auslage heraus und legst Einwickelpapier stattdessen hin (veränderst Inhalt der anderen Variable).
Jetzt steht davor ein Schild in 1 Meter Höhe, dass dies verdeckt, der Fehler bleibt unbemerkt. Nun änderst du das Schild, du veränderst dessen Höhe, so dass die Warenauslage zu sehen ist. Dein Nachbar sieht nun, dass da was fehlt, der Fehler tritt auf. Dabei hatte die Höhe des Schildes nix damit zu tun.
|
|
Ginger
Hält's aus hier
Beiträge: 2
|
Verfasst: So 05.10.08 13:40
|
|
jaenicke
Beiträge: 19273
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 05.10.08 13:42
Nein, es tritt nur zufällig der Fehler nicht mehr auf, weil durch die Veränderung andere Speicherbereiche für folgende Speicheroperationen benutzt werden, denn bei einer Stringoperation werden ggf. neue Strings angelegt o.ä., außerdem ist die Anweisung selbst auch im Speicher, etc. ...
|
|
Tobi482
Beiträge: 135
|
Verfasst: So 05.10.08 14:02
Ok Jungs Danke für eure Hilfe,
ich habe den Fehler gefunden, es war tatsächlich das mit den Melonen. Sobald man einen String initialisiert hat, wurden Speicherbereiche die für den String benutzt wurden "gesäubert" mit 0x00 die später einen Fehler vermieden haben. Ich hatte Arrays vor dem benutzten nicht mit Zeromemory gesäubert. Die initialisierung des Stringspeichers dageben hat die bereiche gesäubert und damit funktionierte isSequenzeOffset.
DANKE FÜR EURE HILFE
Mit frendlichen Grüßen Tobi
|
|
|