2012-03-30 13 views
6

Se lo eseguo in modo che la mia applicazione non risponda fino a trovare tutti i file e li alla listbox la mia domanda è Come posso rendere questa funzione multi-threded per evitare situazioni di non risposta! Sono ancora Delphi novoicericerca file delphi multithreading

procedure TfrMain.FileSearch(const PathName, FileName : string; txtToSearch : string; const InDir : boolean); 
var Rec : TSearchRec; 
    Path : string; 
    txt : string; 
    fh : TextFile; 
    i : integer; 
begin 


Path := IncludeTrailingBackslash(PathName); 
if FindFirst(Path + FileName, faAnyFile - faDirectory, Rec) = 0 then 
try 
    repeat 

    AssignFile(fh, Path + Rec.Name); 
    Reset(fh); 
    Readln(fh,txt); 

    if ContainsStr(txt, txtToSearch) then 
     ListBox1.Items.Add(Path + Rec.Name); 

    until FindNext(Rec) <> 0; 
finally 
    FindClose(Rec); 

end; 

If not InDir then Exit; 

if FindFirst(Path + '*.*', faDirectory, Rec) = 0 then 
try 
    repeat 
    if ((Rec.Attr and faDirectory) <> 0) and (Rec.Name<>'.') and (Rec.Name<>'..') then 
    FileSearch(Path + Rec.Name, FileName, txtToSearch, True); 
    until FindNext(Rec) <> 0; 
finally 
    FindClose(Rec); 
end; 
end; 

risposta

5

si può mettere la roba scansione dei file in un filo e whenver lavoro è finito inviare un messaggio di Windows alla maschera principale, che poi aggiorna la casella di riepilogo (codice non testato, prenderla pseudo codice):

const 
    WM_FILESEARCH_FINISHED = WM_USER + 1; 

TFileSearchThread = class (TThread) 
private 
    FPath  : String; 
    FFileNames : TStringList; 
protected 
    procedure Execute; override; 
public 
    constructor Create (const Path : String); 
    destructor Destroy; override; 
    property FileNames : TStrings read FFileNames; 
end; 

constructor TFileSearchThread.Create (const Path : String); 
begin 
    inherited Create (True); 
    FPath := Path; 
    FFileNames := TStringList.Create; 
end; 

destructor TFileSearchThread.Destroy; 
begin 
    FreeAndNil (FFileNames); 
    inherited; 
end; 

procedure TFileSearchThread.Execute; 
begin 
    // do your file search here, adding each file to FFileNames 
    PostMessage (MainForm.Handle, WM_FILESEARCH_FINISHED, 0, 0); 
end; 

si può usare in questo modo:

Thead := TFileSearchThread.Create (Path); 
Thread.Start; 

e la principale forma avrebbe un gestore di messaggi come questo:

type 
    TMainForm = class(TForm) 
    ListBox1: TListBox; 
    private 
    procedure WMFileSearchFinished (var Msg : TMessage); message WM_FILESEARCH_FINISHED; 
    public 
    { Public declarations } 
    end; 

implementation 

procedure TMainForm.WMFileSearchFinished (var Msg : TMessage); 
begin 
    ListBox1.Items.AddStrings (Thread.FileNames); 
end; 
+1

+1, soluzione semplice e pulita. Non c'è molto che possa andare storto. –

+0

Non dovrebbe il 'PostMessage (MainForm.Handle, WM_FILESEARCH_FINISHED, 0, 0); 'essere usato con' Synchronize'? – kobik

+1

@kobik, non c'è bisogno di preoccuparsi, la proprietà 'Handle' è di sola lettura e la sua lettura è atomica. E deve essere diverso da 0 (il controllo sarebbe morto e non potrebbe ricevere alcun messaggio), quindi il getter non creerà mai 'CreateHandle' cosa fa quando l'handle è 0. Il rischio è l'istanza dell'oggetto stessa, se distruggi 'MainForm' e prova ad accedervi, otterrai AV come al solito. E, Emba ['uses'] (http://edn.embarcadero.com/article/22411) anche questo :-) – TLama