スレッド(TThread)で指定フォルダ以下のファイルを再帰的に探索 ~Delphiソースコード集
Delphiを起動して新規作成を行う
Delphiを起動し、ファイル→新規作成→Windows VCLアプリケーションをクリックする。TButtonを2つと、TMemoを1つドラッグドロップする。Memo1のScrollBarsプロパティをssBothに設定する。
スレッド(TThreadからの派生クラス)用のユニットを作成
ファイル→新規作成→ユニットをクリックする。以下ソースコードを記述し、ファイル名「UThreadSearchFile.pas」として保存する。
unit UThreadSearchFile; interface uses system.sysutils,system.classes,system.strutils; type TSearchFileKind=(sfFileOnly,sfDirectoryOnly,sfFileAndDirectory); TOnSearchFileFind=procedure(Sender:TObject;FindName:String) of object; TThreadSearchFile=class(TThread) private fStl:TStringList;//探索結果リストが入る fPath:String; //初期パス fKind:TSearchFileKind;//探索種別 fOnFind:TOnSearchFileFind;//逐次ファイルフォルダが探索されるイベント procedure SearchFile(path:string);//再帰探索 protected procedure Execute; override; public constructor Create(DirName:String;kind:TSearchFileKind=sfFileOnly); destructor Destroy; override; property OnFind:TOnSearchFileFind write fOnFind; property List:TStringList read fstl; end; implementation { TThreadSearchFile } constructor TThreadSearchFile.Create(DirName:String; kind:TSearchFileKind=sfFileOnly); begin //Suspend状態で開始する inherited Create(true); //処理終了時にオブジェクトを自動破棄する FreeOnTerminate:=True; fPath:=DirName; fKind:=kind; fStl:=TStringList.Create; //ソートする fStl.Sorted:=True; fOnFind:=nil; end; destructor TThreadSearchFile.Destroy; begin fstl.Free; inherited; end; procedure TThreadSearchFile.Execute; begin inherited; //再帰処理を行う SearchFile(fPath); end; procedure TThreadSearchFile.SearchFile(path:string); var f:TSearchRec; ret:Integer; begin if RightStr(path,1)='\' then path:=LeftStr(path,length(path)-1); if not DirectoryExists(path) then exit; //ファイル、フォルダの探索 ret:=FindFirst(path+'\*',faAnyFile,f); while (ret=0) and (not Terminated) do begin if (f.Name<>'.') and (f.Name<>'..') then begin if (f.Attr and faDirectory)=faDirectory then begin //フォルダの場合 if fKind<>sfFileOnly then begin fStl.Add(path+'\'+f.Name); if Assigned(fOnFind) then Synchronize( procedure() begin fOnFind(self,path+'\'+f.Name); end ); end; Self.SearchFile(path+'\'+f.Name); end else begin //ファイルの場合 if fKind<>sfDirectoryOnly then begin fStl.Add(path+'\'+f.Name); if Assigned(fOnFind) then Synchronize( procedure() begin fOnFind(self,path+'\'+f.Name); end ); end; end; end; while (not Terminated) and Suspended do begin //terminateではなく、suspendedの間は待つ sleep(100); end; ret:=FindNext(f); end; FindClose(f); end; end.
Unit1のソースコードを記述
以下のソースコードを記述するunit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.FileCtrl,UThreadSearchFile; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private 宣言 } tsf:TThreadSearchFile; procedure onFindFile(Sender:TObject;FindName:String); procedure onTerminated(Sender:TObject); public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var SelDir:string; begin SelDir:=''; //フォルダ探索の開始 Vcl.FileCtrl.SelectDirectory( '探索開始フォルダの選択', '', SelDir, [sdNewUI,sdShowShares], Self ); if SelDir='' then exit; memo1.Lines.Clear; Button1.Enabled:=false;//開始ボタン Button2.Enabled:=true; //終了ボタン tsf:=TThreadSearchFile.Create(SelDir,sfFileOnly); //逐次ファイル又はフォルダが探索される度にイベント発生 tsf.OnFind:=onFindFile; //フォルダ探索が完了後のイベント tsf.OnTerminate:=onTerminated; //探索開始 tsf.Start; end; procedure TForm1.Button2Click(Sender: TObject); begin //フォルダ探索の停止 if assigned(tsf) then tsf.Terminate; Button1.Enabled:=true; //開始ボタン Button2.Enabled:=false;//終了ボタン end; procedure TForm1.FormCreate(Sender: TObject); begin Button1.Enabled:=true; //開始ボタン Button2.Enabled:=false;//終了ボタン end; procedure TForm1.FormDestroy(Sender: TObject); begin if assigned(tsf) then tsf.Terminate; end; procedure TForm1.onFindFile(Sender: TObject; FindName: String); begin //逐次探索結果を表示する場合 Memo1.Lines.Add(FindName); end; procedure TForm1.onTerminated(Sender: TObject); begin //フォルダ探索完了後にソートされた一覧を一括表示する場合 //memo1.Lines.Assign(tsf.List); tsf:=nil;//FreeOnTerminate=trueの為、破棄は任せる Button1.Enabled:=true; //開始ボタン Button2.Enabled:=false;//終了ボタン end; end.