フォルダの内容が変更されたかどうかをすばやく決定します
-
27-09-2020 - |
質問
どのフォルダに「最近」(特定の間隔内)に変更されているファイルが含まれているかを判断する必要があります。私は、含まれているファイルが変更されたときはいつでもフォルダのデータスタンプが更新されるように見えますが、この現象はツリーを伝播しません。つまり、変更されたファイルを含むフォルダを含むフォルダのDatesTampは更新されません。
この現象を扱うことができますが、プラットフォーム/ファイルシステム/ネットワーク、またはローカルドライブなどに依存します。私はまだ私ができる場所を利用したいと思いますので、trueを返すブール関数が必要ですアプリを実行しているプラットフォーム/ディスクがこの動作をサポートしている場合
木を聴くことはとても嬉しいです。私が避けたいのは、すべてのフォルダ内のすべてのファイルに対してfindfirst / findNextを行う必要があります(言っている)。最後の日以内に、それは大幅な時間を節約するでしょう。
正しい解決策はありません
他のヒント
FindFirstChangeNotification
とFindNextChangeNotification
関数
もう1つのオプションは、 TJvChangeNotify
Jediコンポーネントです。
最新にこのリンクをチェックすることができます
これまでのところ投稿されたソリューションは、彼らが起こるときに通知を得ることについてのものであり、彼らはその目的のためにうまくいくでしょう。あなたが過去を見て、そして何かがリアルタイムで監視するのではなく、最後に変更されたときを見るならば、それは私に取り組む。フォルダツリーを再帰的に検索し、DatesTampsをチェックすること以外はそれをする方法はないと思います。
編集: opのコメントに応答して、ええ、findfirst / findnextを設定する方法があるようには、ファイルではなくディレクトリのみをHITにする方法があります。ただし、このフィルタを使用してファイルの日付の確認をスキップできます.(SearchRec.Attr and SysUtils.faDirectory <> 0)
。それは物事を少し上げるべきです。ファイルの日付をまったく確認しないでください。Windows APIは、Windows APIは、ファイルではなくフォルダのみを問い合わせるだけではありません。
私は私のプロジェクトの1つに対してこの目的のためのコードを書きました。これはfindFirstChangeEnotificationとFindNextChangeEnotification API関数を使用します。 これがコードです(私はプロジェクト固有の部分を削除しました):
/// <author> Ali Keshavarz </author>
/// <date> 2010/07/23 </date>
unit uFolderWatcherThread;
interface
uses
SysUtils, Windows, Classes, Generics.Collections;
type
TOnThreadFolderChange = procedure(Sender: TObject; PrevModificationTime, CurrModificationTime: TDateTime) of object;
TOnThreadError = procedure(Sender: TObject; const Msg: string; IsFatal: Boolean) of object;
TFolderWatcherThread = class(TThread)
private
class var TerminationEvent : THandle;
private
FPath : string;
FPrevModificationTime : TDateTime;
FLatestModification : TDateTime;
FOnFolderChange : TOnThreadFolderChange;
FOnError : TOnThreadError;
procedure DoOnFolderChange;
procedure DoOnError(const ErrorMsg: string; IsFatal: Boolean);
procedure HandleException(E: Exception);
protected
procedure Execute; override;
public
constructor Create(const FolderPath: string;
OnFolderChangeHandler: TOnThreadFolderChange;
OnErrorHandler: TOnThreadError);
destructor Destroy; override;
class procedure PulseTerminationEvent;
property Path: string read FPath;
property OnFolderChange: TOnThreadFolderChange read FOnFolderChange write FOnFolderChange;
property OnError: TOnThreadError read FOnError write FOnError;
end;
/// <summary>
/// Provides a list container for TFolderWatcherThread instances.
/// TFolderWatcherThreadList can own the objects, and terminate removed items
/// automatically. It also uses TFolderWatcherThread.TerminationEvent to unblock
/// waiting items if the thread is terminated but blocked by waiting on the
/// folder changes.
/// </summary>
TFolderWatcherThreadList = class(TObjectList<TFolderWatcherThread>)
protected
procedure Notify(const Value: TFolderWatcherThread; Action: TCollectionNotification); override;
end;
implementation
{ TFolderWatcherThread }
constructor TFolderWatcherThread.Create(const FolderPath: string;
OnFolderChangeHandler: TOnThreadFolderChange; OnErrorHandler: TOnThreadError);
begin
inherited Create(True);
FPath := FolderPath;
FOnFolderChange := OnFolderChangeHandler;
Start;
end;
destructor TFolderWatcherThread.Destroy;
begin
inherited;
end;
procedure TFolderWatcherThread.DoOnFolderChange;
begin
Queue(procedure
begin
if Assigned(FOnFolderChange) then
FOnFolderChange(Self, FPrevModificationTime, FLatestModification);
end);
end;
procedure TFolderWatcherThread.DoOnError(const ErrorMsg: string; IsFatal: Boolean);
begin
Synchronize(procedure
begin
if Assigned(Self.FOnError) then
FOnError(Self,ErrorMsg,IsFatal);
end);
end;
procedure TFolderWatcherThread.Execute;
var
NotifierFielter : Cardinal;
WaitResult : Cardinal;
WaitHandles : array[0..1] of THandle;
begin
try
NotifierFielter := FILE_NOTIFY_CHANGE_DIR_NAME +
FILE_NOTIFY_CHANGE_LAST_WRITE +
FILE_NOTIFY_CHANGE_FILE_NAME +
FILE_NOTIFY_CHANGE_ATTRIBUTES +
FILE_NOTIFY_CHANGE_SIZE;
WaitHandles[0] := FindFirstChangeNotification(PChar(FPath),True,NotifierFielter);
if WaitHandles[0] = INVALID_HANDLE_VALUE then
RaiseLastOSError;
try
WaitHandles[1] := TerminationEvent;
while not Terminated do
begin
//If owner list has created an event, then wait for both handles;
//otherwise, just wait for change notification handle.
if WaitHandles[1] > 0 then
//Wait for change notification in the folder, and event signaled by
//TWatcherThreads (owner list).
WaitResult := WaitForMultipleObjects(2,@WaitHandles,False,INFINITE)
else
//Wait just for change notification in the folder
WaitResult := WaitForSingleObject(WaitHandles[0],INFINITE);
case WaitResult of
//If a change in the monitored folder occured
WAIT_OBJECT_0 :
begin
// notifiy caller.
FLatestModification := Now;
DoOnFolderChange;
FPrevModificationTime := FLatestModification;
end;
//If event handle is signaled, let the loop to iterate, and check
//Terminated status.
WAIT_OBJECT_0 + 1: Continue;
end;
//Continue folder change notification job
if not FindNextChangeNotification(WaitHandles[0]) then
RaiseLastOSError;
end;
finally
FindCloseChangeNotification(WaitHandles[0]);
end;
except
on E: Exception do
HandleException(E);
end;
end;
procedure TFolderWatcherThread.HandleException(E: Exception);
begin
if E is EExternal then
begin
DoOnError(E.Message,True);
Terminate;
end
else
DoOnError(E.Message,False);
end;
class procedure TFolderWatcherThread.PulseTerminationEvent;
begin
/// All instances of TFolderChangeTracker which are waiting will be unblocked,
/// and blocked again immediately to check their Terminated property.
/// If an instance is terminated, then it will end its execution, and the rest
/// continue their work.
PulseEvent(TerminationEvent);
end;
{ TFolderWatcherThreadList }
procedure TFolderWatcherThreadList.Notify(const Value: TFolderWatcherThread;
Action: TCollectionNotification);
begin
if OwnsObjects and (Action = cnRemoved) then
begin
/// If the thread is running, terminate it, before freeing it.
Value.Terminate;
/// Pulse global termination event to all TFolderWatcherThread instances.
TFolderWatcherThread.PulseTerminationEvent;
Value.WaitFor;
end;
inherited;
end;
end.
.
これは2つのクラスを提供します。変更用のフォルダを監視するスレッドクラス、および変更が検出された場合は、OnFolderChangeイベントを介して現在の変更時間と以前の変更時間を返します。監視スレッドのリストを格納するためのリストクラス。このリストは、スレッドがリストから削除されたときに自動的に各スレッドを終了します。
私はそれがあなたを助けることを願っています。