Autor |
Beitrag |
del1312
      
Beiträge: 190
|
Verfasst: Fr 20.08.10 12:25
Hallo Leute,
bastel grad an einem kleinen Tool, welches mir auf der Festplatte bestimmte Daten sucht. Das ganze mach ich so:
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:
| procedure GetFilesInDirectory(Directory: string; const Mask: string; List: TStrings; WithSubDirs, ClearList: Boolean);
procedure ScanDir(const Directory: string); var SR: TSearchRec; begin if FindFirst(Directory + Mask, faAnyFile and not faDirectory, SR) = 0 then try repeat List.Add(Directory + SR.Name) until FindNext(SR) <> 0; finally FindClose(SR); end;
if WithSubDirs then begin if FindFirst(Directory + '*.*', faAnyFile, SR) = 0 then try repeat if ((SR.attr and faDirectory) = faDirectory) and (SR.Name <> '.') and (SR.Name <> '..') then ScanDir(Directory + SR.Name + '\'); until FindNext(SR) <> 0; finally FindClose(SR); end; end; end;
begin List.BeginUpdate; try if ClearList then List.Clear; if Directory = '' then Exit; if Directory[Length(Directory)] <> '\' then Directory := Directory + '\'; ScanDir(Directory); finally List.EndUpdate; end; end; |
Aufrufen tue ich das dann hier:
Delphi-Quelltext 1:
| GetFilesInDirectory(Pfad, '*-2010_*', Listbox1.Items, True, True); |
Jetzt meine Frage, da es manchmal doch ne Weile dauert möchte ich gerne so eine ProgressBar einbauen.
Nur weiss ich nicht so recht wie ich die so einbaue das sie während des Prozesses läuft.
Hatte das mit einem Timer probiert, aber der schein auch nicht in Hintergrund weiter zulaufen während
die HDD durchsucht wird:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button1Click(Sender: TObject); begin Pfad:=Edit1.Text; Timer1.Enabled:=true; ProgressBar1.Visible:=true; GetFilesInDirectory(Pfad, '*-2010_*', Listbox1.Items, True, True); listcount:=ListBox1.Count; Timer1.Enabled:=false; ProgressBar1.Visible:=false; ProgressBar1.Position :=0; ShowMessage('Es wurden: '+ IntToStr(listcount)+ ' passende Datensätze gefunden!'); end; |
und der im Timer stand das:
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TForm1.Timer1Timer(Sender: TObject); begin ProgressBar1.Position :=ProgressBar1.Position +1; ProgressBar1.Update ; end; |
Ich vermute ich muss
Delphi-Quelltext 1:
| GetFilesInDirectory(Pfad, '*-2010_*', Listbox1.Items, True, True); |
irgendwie in eine Schleife bauen oder? Kann mir da bitte einer helfen oder nen Tipp geben?
Noch ne Frage zu der ProgressBar. Wie kann ich die eigentlich so einrichten das sie auch korrekt
den Status anzeigt? Also ich meine irgendwo muss das errechnet werden, so und soviel % sind bereits abgearbeitet damit
die Bar überhaupt richtig anzeigt oder?
DANKE schon mal für eure Hilfe!
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Fr 20.08.10 12:37
Du könntest GetFilesInDirectory eine Paramter eines ProgressDialogs mitgegeben, wenn dieser ASSIGNED ist in der Schleife updaten.
|
|
ALF
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Fr 20.08.10 13:24
Hi, dazu müsstest Du aber vorher wissen, wie viel Dateien es auf Deiner Festplatte gibt!
Sonst kannst du keine prozentuale Anzeige machen wie viel oder wie lange es noch dauern wird.
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Fr 20.08.10 13:40
Geht doch .... so:
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:
| procedure GetFilesInDirectory(Directory: string; const Mask: string; List: TStrings; WithSubDirs, ClearList: Boolean;PG:TProgressbar); var Cur:TCursor;
Function CountDir(const Directory: string):Integer; var SR: TSearchRec; begin Result := 0;
if FindFirst(Directory + Mask, faAnyFile and not faDirectory, SR) = 0 then try repeat inc(result); until FindNext(SR) <> 0; finally FindClose(SR); end; if WithSubDirs then begin if FindFirst(Directory + '*.*', faAnyFile, SR) = 0 then try repeat if ((SR.attr and faDirectory) = faDirectory) and (SR.Name <> '.') and (SR.Name <> '..') then Result := Result + CountDir(Directory + SR.Name + '\'); until FindNext(SR) <> 0; finally FindClose(SR); end; end; end;
procedure ScanDir(const Directory: string); var SR: TSearchRec; begin
if FindFirst(Directory + Mask, faAnyFile and not faDirectory, SR) = 0 then try repeat List.Add(Directory + SR.Name); if Assigned(PG) then begin pg.Position := List.Count; end;
until FindNext(SR) <> 0; finally FindClose(SR); end;
if WithSubDirs then begin if FindFirst(Directory + '*.*', faAnyFile, SR) = 0 then try repeat if ((SR.attr and faDirectory) = faDirectory) and (SR.Name <> '.') and (SR.Name <> '..') then ScanDir(Directory + SR.Name + '\'); until FindNext(SR) <> 0; finally FindClose(SR); end; end; end;
begin Cur := Screen.Cursor; try Screen.Cursor := crHourGlass; if Assigned(PG) then pg.State := pbsNormal; List.BeginUpdate;
if ClearList then List.Clear; if Directory = '' then Exit; if Directory[Length(Directory)] <> '\' then Directory := Directory + '\'; if Assigned(PG) then pg.Max := CountDir(Directory); ScanDir(Directory); finally List.EndUpdate; if Assigned(PG) then pg.State := pbsPaused;
end; Screen.Cursor := Cur; end; |
|
|
del1312 
      
Beiträge: 190
|
Verfasst: Fr 20.08.10 13:54
DANKE! Also ich habs mal eingebaut und hier noch die Progressbar1 eingetragen, das war doch richtig oder?
GetFilesInDirectory(Pfad, '*-2010_*', Listbox1.Items, True, True, Progressbar1);
Also er macht erstmal was, aber warum wird die Bar gelb und so richtig flüssig ist es auch nicht, bzw erst kommt
nichts und dann ist halb und dann voll. Geht warhscheinlich nicht anders oder? Na erstmal vielen DANK bummi!!!!
|
|
ALF
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Fr 20.08.10 13:56
Jo, bummi ,damit hat er aber leider keine Progressanzeige wie lange es noch dauert
Problem mit Progessbar ist, das Du vorher erst einmal die gesammte Platte scannen must um festzustellen wie viel Dateien da drauf sind, um anzuzeigen wie lange es noch dauern wird!
Andere Möglichkeit, etwas schneller, den belegten Platz auf der Festplatte zu nehmen und dann beim Scannen den belegten Platz, (nicht Dateigrösse), den eine Datei einimmt, zu addieren um somit eine Progressanzeige zu verwirklichen! Ob dies aber sauber ist weis ich nicht!
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
del1312 
      
Beiträge: 190
|
Verfasst: Fr 20.08.10 13:59
Hm ok dann muss ich das wohl weglassen, schade. Vielen Dank für eure Hilfe
|
|
Tankard
      

Beiträge: 217
Erhaltene Danke: 96
|
Verfasst: Fr 20.08.10 14:24
hallo,
ruf in der schleife ab und zu mal
Application.ProcessMessages
auf. sonst werden die messages nicht abgearbeitet und deine ganze application scheint für den benutzer zu stehen. das bedeutet auch das die progressbar sich nicht bewegt und erst nach beenden der suche neu gezeichnet wird.
gruss
tankard
|
|
ALF
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Fr 20.08.10 14:39
Warum so schnell aufgeben? Wenn du nicht unbedingt im Windows Ordner selbst was suchen willst, sondern nur in den Bereichen, Programme und alles was für den User gültigkeit hat, pro Partition/Fetsplatte ist auch dieses sehr flink!
Zumal man ja unter umständen den Scann für die Anzahl der vorhandenen Dateien, ja auch in einen Thread auslagern kann (der muss ja nur die Dateien Zählen nix vergleichen) und dann bei Deinem eigentlichen Suchvorgang die anzahl der Dateien für Deine Progressbar zu aktualliesieren! Ist nur so eine Idee
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Fr 20.08.10 15:52
Wenn ich nicht grad total bescheurt bin, dann braucht bummies Code DOPPELT so lange wie der normale Code, weil er zweimal alle Dateien sucht...also das wäre ja ein Verbrechen
 Das einfachste wäre wohl so eine tolle Windows-"Ich bin noch nicht abgestürzt"-Leiste hinzumachen, die einfach immer durchläuft
In der Machart:
www.linnekogel.de/im...ayout/ladebalken.gif
Das ist immer gut wenn man garkeine Ahnung hat was los ist. Super ist, wenn das Programm abgestürzt ist und das Ding dreht sich trotzdem weiter
 Dann könntest du, wenn du immer die ganze Platte durchsucht (was ich nicht empfehlen würde) auch die Zeit messen, die du beim ersten mal brauchst. Beim zweiten mal Suchen verwendest du die als ProgressBar.Max. Und du misst wieder die Zeit, mittelst die beiden Zeiten usw. Vorteil: Braucht garkeine Zeit und nach paarmal Suchen sollte es einigermaßen passen.
 Wenn du die Dateien erst zählen willst, ist das meiner Meinung nach Quatsch...denn in dem Moment bist du ja dann schon fertig, da du ja nur die Dateien suchst. Also in dem Moment wo du sie mitzählst, warst du ja schon bei ihr. Anders ist es, wenn du die Dateien z.B. kopierst. Dann fällt die Zeit, die du zum zählen verwendest, nicht so ins Gewicht, da das Kopieren viel länger dauert.
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
del1312 
      
Beiträge: 190
|
Verfasst: Fr 20.08.10 17:08
Stimmt das einfach mit ner Windows-"Ich bin noch nicht abgestürzt"-Leiste ist ne super Idee, das werd ich mir glatt mal anschauen, danke!
|
|
ALF
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Fr 20.08.10 17:18
Dann könnte er auch den Cursor dafür setzten, wie @Bummi es vorgeschlagen hat!
Xion hat folgendes geschrieben : | Das ist immer gut wenn man garkeine Ahnung hat was los ist. Super ist, wenn das Programm abgestürzt ist und das Ding dreht sich trotzdem weiter  |
Halt der Nachteil!
Xion hat folgendes geschrieben : | Dann könntest du, wenn du immer die ganze Platte durchsucht (was ich nicht empfehlen würde) |
Würd ich auch nicht empfehlen, nur manchmal brauch man es halt
Xion hat folgendes geschrieben : | auch die Zeit messen, die du beim ersten mal brauchst. Beim zweiten mal Suchen verwendest du die als ProgressBar.Max. Und du misst wieder die Zeit, mittelst die beiden Zeiten usw. Vorteil: Braucht garkeine Zeit und nach paarmal Suchen sollte es einigermaßen passen. |
Auf sowas würde noch nicht mal ich kommen
Xion hat folgendes geschrieben : | Wenn du die Dateien erst zählen willst, ist das meiner Meinung nach Quatsch.. |
Nein, er soll ja erst vor den Suchen Zählen, wenn er mit Progressbar arbeiten will, nicht zur gleichen Zeit wenn er sucht. Habe ich aber deutlich geschrieben
Dabei hab ich ihm 3 Möglichkeiten aufgezählt! Ne 4. währe, nur den Inhalt des jeweiligen Ordner zu zählen und dann im Ordner zu suchen. Wenn man mit Progressbar arbeiten will!!!
Das bleibt aber jedem selbst überlassen
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Fr 20.08.10 20:40
Längere Operationen auf dem UI Thread laufen zu lassen ist für mich zu mindest Tabu. Ich würde die Suche in einem Thread machen. Dort kannst den jeweils den aktuellen Stand über ein Property auslesbar machen (die muss threadsafe sein). Der Progressbar liest dann z.B. über einen Timer regelmässig den Wert ab. Falls der Progress unbekannt desto einfacher (dann lässt du die Geschichte einfach weg).
Beim Listbox1.Items müsstest du bei Threads aufpassen, da diese nicht threadsafe ist. Da du ja aber sowieso BeginUpdate/EndUpdate verwendest bist du offenbar nicht am Zwischenresultat interessiert. D.h. dann würde ich die Methode eine eigene TStringList erzeugen lassen und diese über einen Callback zurückgeben.
|
|
elundril
      
Beiträge: 3747
Erhaltene Danke: 123
Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
|
Verfasst: Fr 20.08.10 20:57
Es gibt Dinge die "darf" man einfach nicht in einen Thread auslagern, weil es einfach vom Design her unnötig ist. Sieh Luckys Thread-Tutorial.
_________________ This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Fr 20.08.10 21:10
Die Lösung mit Application.ProcessMessages oder einer blockierenden UI würde ich absolut davon abraten. Das Design mit Threads ist State of the Art. Ich sag ja nicht überall, aber Festplatte durchsuchen ist dafür bestens geeignet.
In neuen Technologien wie Silverlight gibt es für längere Operationen überhaupt keine Blocking Calls mehr sondern ausschliesslich asynchrone Pendants.
Gutes Design ist, wenn der UI Thread zu keiner Zeit stillsteht. Wenn du die UI eine Sekunde lang blockierst hast du was falsch gemacht. Wenn sie 5 Sekunden still steht heisst es seitens Windows nur noch "Not Responding".
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Sa 21.08.10 17:39
Vielleicht ist mal das alte DIR ganz sinnvoll zur Ermittlung der Dateienanzahl:
DIR "Pfad" /S >"Textdatei"
dann steht in der Textdatei die Anzahl der Dateien in der vorletzten Zeile.
Du musst dan nur folgendes Aufrufen:
Habe das Starten in eine Prozedur Progstarten geschrieben:
Ich glaube Uses Windows muss dazu in der Unit sein, sionst funktioniert das Ganze nicht.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure ProgStarten(const DateiName: String; const Parameter: String=''; const immer : boolean = FALSE); var Erg : integer; begin if not(FileExists(Dateiname)) and not(immer) then begin Fehler('Das Programm ['+Dateiname+'] existiert nicht! In den Optionen bitte korrigieren.'); Exit; end; Erg := ShellExecute(Application.Handle,'open',PChar(DateiName),PChar(Parameter),PChar(ExtractFilePath(DateiName)),SW_SHOW); if Erg<32 then Mitteilung('Beim Start des Programms '+Dateiname+' ist ein Fehler aufgetreten!'); end; |
Du rufst dann das Dir mit Delphi-Quelltext 1:
| Progstarten('DIR','/S > '+Dateiname,TRUE); | auf
Dann musst Du nur die vorletzte Zeile der Textdatei einlesen und daraus de Anzahl der Dateien auslesen.
Für die Restzeit brauchst Du nur die Anzahl, die derzeitige Position, die Startzeit und die aktuelle Zeit
Delphi-Quelltext 1:
| Restzeit := (now - Startzeit)*(Anzahl - n)/Anzahl; |
Das gibst Du unter dem Progressbar aus.
Am Besten Du nimmst die angehängte Unit für den Progressbar. Dann erscheint dieser in einem Extrafenster und der Vorgang kann jederzeit abgebrochen werden.
Hierzu wird die globale Variable PROCAbbruch auf TRUE gesetzt.
Den Fortschritt akitivierst Du mit Delphi-Quelltext 1:
| FortschrittBeginnen(Anzahl, TRUE/FALSE); |
innerhalb der Schleife: Delphi-Quelltext 1:
| FortschrittAktualisieren(Text); |
und am Ende: Delphi-Quelltext
Über Aufzählen von n oder I oder sonst was - kein Gedanke daran. Steht alles in der Unit.
Nur am Anfang einmal die Gesamtzahl vorgeben!
Ich habe es mit Delphi 5 geschrieben. Hoffentlich funktioniert dies auch mit anderen Versionen.
Moderiert von Narses: Delphi-Tags hinzugefügt
Einloggen, um Attachments anzusehen!
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 21.08.10 17:58
Was hat es für einen Sinn einen Kommandozeilenbefehl zu benutzen und die Ausgabe auszulesen? Der Effekt ist nur, dass dein Formular erst recht nicht mehr reagiert, weil du keine Möglichkeit hast während der Ausführung und dem Warten darauf etwas anderes zu machen oder Rechenzeit freizugeben.
Klar kannst du dann das wiederum in einen Thread legen, aber das kannst du dann auch gleich mit dem Delphicode zur Suche machen.
Ja, und dann willst du die Anzahl der gefundenen Dateien für den Fortschritt der erneuten (!!) Suche benutzen?!?
Du hast dann doch schon die Liste der Dateien...
Ja, und zuguterletzt:
"dir" ist keine Exe, dementsprechend musst du den Befehl auch als Parameter an cmd übergeben und kannst den Befehl nicht als Dateiname an ShellExecute übergeben...
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Sa 21.08.10 21:39
Ich habe so etwas mal realisiert: www.michael-puff.de/...mierung/Delphi/Units -> MpuDriveTools.pas
Mit der Unit geht so was. Allerdings sollte man sich im Klaren sein, dass man immer Performance Einbußen hat.
|
|
ssb-blume
      
Beiträge: 375
Erhaltene Danke: 7
XP, W7, W8
Deutschland
|
Verfasst: So 22.08.10 09:10
Hallo,
habe mal eine sehr alte Version für dieses Problem erstellt, siehe Anhang (.ZIP)
Es sind alle Quellen dabei, auch eine kurze Doc.
Ich hoffe, Du kannst damit etwas anfangen!
Hansi
Einloggen, um Attachments anzusehen!
_________________ Brain: an apparatus with which we think we think.
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: Di 24.08.10 22:35
|
|
|