Windows提供了一组API用于检测目录是否变化。
下面是一个检测目录变化的控件。
{$D-}
unit DiskChangeEx;
uses
; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls;
type
; TNotifyFilterTypeEx = (FILE_NAME,
; ; ; ; ; ; ; ; ; ; ; ; ;DIR_NAME,
; ; ; ; ; ; ; ; ; ; ; ; ;ATTRIBUTES,
; ; ; ; ; ; ; ; ; ; ; ; ;SIZE,
; ; ; ; ; ; ; ; ; ; ; ; ;LAST_WRITE,
; ; ; ; ; ; ; ; ; ; ; ; ;SECURITY);
; TNotifyFiltersEx = set of TNotifyFilterTypeEx;
; TFileChangeEventEx = procedure (Sender : TObject; NewFiles, DeletedFiles : TStringList) of object;
; TDiskChangeNotifyEx = class;
; TScanThread = class (TThread)
; private
; ; DCN : TDiskChangeNotifyEx;
; ; IsInit : boolean;
; ; EnableNotify : boolean;
; ; procedure NotifyDCN;
; public
; ; constructor Create (DoInit : boolean);
; ; procedure Execute; override;
; end;
; TDiskWatchThreadEx = class (TThread)
; private
; ; DCN : TDiskChangeNotifyEx;
; ; procedure NotifyDCN;
; public
; ; procedure Execute; override;
; end;
; TDiskChangeNotifyEx = class(TComponent)
; private
; ; WatchThread : TDiskWatchThreadEx;
; ; ScanThread : TScanThread;
; ; FWatchSubTree : boolean;
; ; FEnabled : boolean;
; ; FWatchDir : string;
; ; FOnDiskChange : TNotifyEvent;
; ; FNotifyFilter : TNotifyFiltersEx;
; ; NotifyFilterW : word;
; ; FFileChangeEvent : ;TFileChangeEventEx;
; ; FFileExts : string;
; ; FUseTimer : boolean;
; ; FTimerDelay : integer;
; ; FMaintainedDirList : boolean;
; ; FTimer : TTimer;
; ; procedure CreateWatchThread;
; ; procedure DestroyWatchThread;
; protected
; ; procedure SetWatchSubTree (Value : boolean);
; ; procedure SetEnabled (Value : boolean);
; ; procedure SetWatchDir (Value : string);
; ; procedure SetNotifyFilter (Filters : TNotifyFiltersEx);
; ; procedure ScanTerminated (Completed : boolean);
; ; procedure ChangeNotification;
; ; procedure DoNotification (Sender : TObject);
; public
; ; Busy : boolean;
; ; CurrentDirList : TStringList;
; ; NewFilesList : TStringList;
; ; DeletedFilesList : TStringList;
; ; constructor Create (AOwner : TComponent); override;
; ; destructor Destroy; override;
; published
; ; property WatchDir : string read FWatchDir write SetWatchDir;
; ; property WatchSubTree : boolean read FWatchSubTree write SetWatchSubTree default true;
; ; property Enabled : boolean read FEnabled write SetEnabled default false;
; ; property NotifyFilter : TNotifyFiltersEx read FNotifyFilter write SetNotifyFilter;
; ; property FileExtensions : string read FFileExts write FFileExts;
; ; property UseTimer : boolean read FUseTimer write FUseTimer;
; ; property TimerDelay : integer read FTimerDelay write FTimerDelay;
; ; property MaintainedDirList : boolean read FMaintainedDirList write FMaintainedDirList;
; ; property OnDiskChange : TNotifyEvent read FOnDiskChange write FOnDiskChange;
; ; property OnFilesChanged : TFileChangeEventEx read FFileChangeEvent write FFileChangeEvent;
; end;
procedure Register;
// ------------------------------------------------------------------------------ //
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; implementation
// ------------------------------------------------------------------------------ //
procedure Register;
begin
; RegisterComponents('Gamit', [TDiskChangeNotifyEx]);
end;
// ------------------------------------------------------------------------------ //
constructor TScanThread.Create (DoInit : boolean);
begin
; inherited Create (true); // Create suspended
; IsInit := DoInit;
; EnableNotify := true;
end;
procedure TScanThread.NotifyDCN;
begin
; DCN.ScanTerminated (not Terminated);
end;
procedure TScanThread.Execute;
var
; SRes : integer;
; SRec : TSearchRec;
; NewDList, NewFiles, DeletedFiles : TStringList;
; i : integer;
begin
; DCN.Busy := true;
; NewDList := TStringList.Create;
; NewFiles := TStringList.Create;
; DeletedFiles := TStringList.Create;
; SRes := FindFirst (DCN.WatchDir +'/*.*', faAnyFile, SRec);
; while (not Terminated) and (SRes = 0) do begin
; ; if (SRec.Attr <> faDirectory) and
; ; ; ;((DCN.FileExtensions = '') or (Pos (ExtractFileExt (SRec.Name), DCN.FileExtensions) > 0)) then
; ; ; NewDList.Add (SRec.Name);
; ; SRes := FindNext (SRec);
; end;
; SysUtils.FindClose (SRec);
; if (not Terminated) and (not IsInit) then begin
; ; for i := 0 to NewDList.Count - 1 do begin
; ; ; if (Terminated) then Break;
; ; ; if (DCN.CurrentDirList.IndexOf (NewDList ) = -1) then
; ; ; ; NewFiles.Add (NewDList );
; ; end;
; ; for i := 0 to DCN.CurrentDirList.Count - 1 do begin
; ; ; if (Terminated) then Break;
; ; ; if (NewDList.IndexOf (DCN.CurrentDirList ) = -1) then
; ; ; ; DeletedFiles.Add (DCN.CurrentDirList );
; ; end;
; end;
; if (not Terminated) then begin
; ; DCN.CurrentDirList.Assign (NewDList);
; ; DCN.NewFilesList.Assign (NewFiles);
; ; DCN.DeletedFilesList.Assign (DeletedFiles);
; end;
; NewDList.Free;
; NewFiles.Free;
; DeletedFiles.Free;
;
; if (EnableNotify) then
; ; Synchronize (NotifyDCN);
end;
// ------------------------------------------------------------------------------ //
procedure TDiskWatchThreadEx.NotifyDCN;
begin
; DCN.ChangeNotification;
end;
procedure TDiskWatchThreadEx.Execute;
var
; TempArr : array [0..Max_Path-1] of char;
; AHandle : THandle;
begin
; AHandle := FindFirstChangeNotification (StrPCopy (TempArr, DCN.WatchDir),
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; DCN.WatchSubTree,
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; DCN.NotifyFilterW);
; while (not Terminated) and (DCN <> nil) do begin
; ; WaitForSingleObject (AHandle, INFINITE);
; ; //Synchronize (NotifyDCN);
; ; NotifyDCN;
; ; FindNextChangeNotification (AHandle);
; end;
; FindCloseChangeNotification (AHandle);
end;
// ------------------------------------------------------------------------------ //
constructor TDiskChangeNotifyEx.Create (AOwner : TComponent);
begin
; inherited Create (AOwner);
; WatchThread := nil;
; ScanThread := nil;
; FWatchDir := '';
; FWatchSubTree := true;
; FEnabled := false;
; FNotifyFilter := [FILE_NAME, DIR_NAME, ATTRIBUTES, SIZE, LAST_WRITE];
; FFileExts := '';
; FUseTimer := true;
; FTimerDelay := 1000;
; FMaintainedDirList := true;
; Busy := false;
; if (not (csDesigning in ComponentState)) then begin
; ; CurrentDirList := TStringList.Create;
; ; NewFilesList := TStringList.Create;
; ; DeletedFilesList := TStringList.Create;
; ; FTimer := TTimer.Create (nil);
; ; FTimer.Enabled := false;
; ; FTimer.OnTimer := DoNotification;
; end;
end;
destructor TDiskChangeNotifyEx.Destroy;
begin
; if (not (csDesigning in ComponentState)) then begin
; ; Enabled := false;
; ; CurrentDirList.Free;
; ; NewFilesList.Free;
; ; DeletedFilesList.Free;
; ; FTimer.Free;
; end;
; inherited Destroy;
end;
procedure TDiskChangeNotifyEx.SetWatchSubTree (Value : boolean);
begin
; if (FWatchSubTree <> Value) then begin
; ; FWatchSubTree := Value;
; ; if (Enabled) then begin
; ; ; Enabled := false;
; ; ; Enabled := true;
; ; end;
; end;
end;
procedure TDiskChangeNotifyEx.SetEnabled (Value : boolean);
begin
; if (Value) and (csDesigning in ComponentState) then begin
; ; ShowMessage ('Set to true at runtime only');
; ; Exit;
; end;
; if (not (csDesigning in ComponentState)) and (FEnabled <> Value) then begin
; ; FEnabled := Value;
; ; if (FEnabled) then begin
; ; ; if (MaintainedDirList) then begin // Build initial file list
; ; ; ; ScanThread := TScanThread.Create (true);
; ; ; ; ScanThread.DCN := Self;
; ; ; ; ScanThread.FreeOnTerminate := true;
; ; ; ; ScanThread.Resume;
; ; ; ; ScanThread.EnableNotify := false;
; ; ; ; ScanThread.WaitFor;
; ; ; ; ScanThread := nil;
; ; ; end;
; ; ; FTimer.Enabled := false;
; ; ; if (UseTimer) then
; ; ; ; FTimer.Interval := TimerDelay;
; ; ; CreateWatchThread;
; ; end
; ; else begin
; ; ; DestroyWatchThread;
; ; ; if (Assigned (ScanThread)) then
; ; ; ; ScanThread.Terminate;
; ; end;
; end;
end;
procedure TDiskChangeNotifyEx.SetWatchDir (Value : string);
begin
; if (CompareText (FWatchDir, Value) <> 0) then begin
; ; FWatchDir := Value;
; ; if (Enabled) then begin
; ; ; Enabled := false;
; ; ; Enabled := true;
; ; end;
; end;
end;
procedure TDiskChangeNotifyEx.SetNotifyFilter (Filters : TNotifyFiltersEx);
begin
; FNotifyFilter := Filters;
; NotifyFilterW := 0;
; if (FILE_NAME in Filters) ;then NotifyFilterW := NotifyFilterW or FILE_NOTIFY_CHANGE_FILE_NAME;
; if (DIR_NAME in Filters) ; then NotifyFilterW := NotifyFilterW or FILE_NOTIFY_CHANGE_DIR_NAME;
; if (ATTRIBUTES in Filters) then NotifyFilterW := NotifyFilterW or FILE_NOTIFY_CHANGE_ATTRIBUTES;
; if (SIZE in Filters) ; ; ; then NotifyFilterW := NotifyFilterW or FILE_NOTIFY_CHANGE_SIZE;
; if (LAST_WRITE in Filters) then NotifyFilterW := NotifyFilterW or FILE_NOTIFY_CHANGE_LAST_WRITE;
; if (SECURITY in Filters) ; then NotifyFilterW := NotifyFilterW or FILE_NOTIFY_CHANGE_SECURITY;
; if (Enabled) then begin
; ; Enabled := false;
; ; Enabled := true;
; end;
end;
procedure TDiskChangeNotifyEx.CreateWatchThread;
begin
; WatchThread := TDiskWatchThreadEx.Create (true);
; WatchThread.DCN := self;
; WatchThread.FreeOnTerminate := true;
; WatchThread.Resume;
end;
procedure TDiskChangeNotifyEx.DestroyWatchThread;
begin
; if (Assigned (WatchThread)) then begin
; ; WatchThread.Terminate;
; ; WatchThread := nil;
; end;
end;
procedure TDiskChangeNotifyEx.ScanTerminated (Completed : boolean);
begin
; if (Completed) and ((NewFilesList.Count > 0) or (DeletedFilesList.Count > 0)) then
; ; OnFilesChanged (Self, NewFilesList, DeletedFilesList);
; ScanThread := nil;
; Busy := false;
end;
procedure TDiskChangeNotifyEx.ChangeNotification;
begin
; FTimer.Enabled := false;
; if (Assigned (ScanThread)) then begin
; ; ScanThread.Terminate;
; ; ScanThread.WaitFor;
; end;
; if (UseTimer) then
; ; FTimer.Enabled := true
; else
; ; DoNotification (nil);
end;
procedure TDiskChangeNotifyEx.DoNotification (Sender : TObject);
begin
; FTimer.Enabled := false;
; if (MaintainedDirList) then begin
; ; ScanThread := TScanThread.Create (not Assigned (OnFilesChanged));
; ; ScanThread.DCN := Self;
; ; ScanThread.FreeOnTerminate := true;
; ; ScanThread.Resume;
; end;
; if (Assigned (OnDiskChange)) then
; ; OnDiskChange (Self);
end;
end.