快速确定文件夹内容是否已被修改

我需要确定哪些文件夹包含最近修改过的文件(在一定的时间间隔内)。 我注意到文件夹datestamps似乎得到更新,每当一个包含的文件被修改,但此行为不向上传播树,即包含包含修改后的文件的文件夹的文件夹的date戳没有得到更新。

我可以处理这种行为,但我怀疑这取决于平台/文件系统/networking或本地驱动器等,我仍然想利用它,我可以,所以我需要一个布尔函数返回true,如果平台/磁盘运行我的应用程序支持这种行为。

我很高兴在树上recursion。 我想要避免的是,必须为每个文件夹中的每个文件夹执行FindFirst / FindNext,以查看是否有人在最后一天被修改 – 如果我可以避免对没有修改date戳的文件夹在最后一天内将节省大量的时间。

检查FindFirstChangeNotificationFindNextChangeNotification函数,另一个选项是使用TJvChangeNotify JEDI组件。

附加地,你可以检查这个链接

  • 获取目录更改通知

到目前为止发布的解决方案是关于在发生通知时获取通知,并且为此目的他们将很好地工作。 如果你想看看过去,看看什么时候上一次改变了,而不是实时监控它,那么它会变得更加诡计。 我认为除了递归搜索文件夹树和检查日期戳以外,没有办法做到这一点。

编辑:在回应OP的评论,是的,它看起来没有任何方法来配置FindFirst / FindNext只命中目录而不是文件。 但是你可以跳过使用这个过滤器检查文件的日期: (SearchRec.Attr and SysUtils.faDirectory <> 0) 。 这应该会加快一点。 根本不检查文件的日期。 但是,您可能仍然需要扫描所有内容,因为Windows API不提供任何方式(我知道)仅查询文件夹而不查询文件。

我为我的一个项目编写了一个代码。 这使用FindFirstChangeNotification和FindNextChangeNotification 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. 

这提供了两个类; 一个线程类监视文件夹的变化,如果检测到变化,它将通过OnFolderChange事件返回当前的变化时间和以前的变化时间。 还有一个用于存储监视线程列表的列表类。 该列表在线程从列表中移除时自动终止每个自己的线程。

我希望它可以帮助你。

你应该看看http://help.delphi-jedi.org/item.php?Id=172977这是一个现成的解决方案&#x3002; 如果你不想下载和安装整个JVCL(这是一个伟大的代码;)),你可能想看到在线文件源 – http://jvcl.svn.sourceforge.net/viewvc/jvcl/trunk /jvcl/run/JvChangeNotify.pas?revision=12481&view=markup