Déterminer rapidement si un contenu de dossier a été modifié

Je dois déterminer quels dossiers contiennent des fichiers modifiés “récemment” (dans un certain intervalle). Je remarque que les horodatages des dossiers semblent être mis à jour chaque fois qu’un fichier contenu est modifié, mais ce comportement ne se propage pas dans l’arborescence, c’est-à-dire que l’horodatage du dossier contenant le dossier contenant le fichier modifié n’est pas mis à jour.

Je peux travailler avec ce comportement, mais je pense que cela dépend de la plate-forme / du système de fichiers / du réseau ou du lecteur local, etc. Je voudrais quand même en profiter, donc j’ai besoin d’une fonction booléenne pour retourner true / disk en cours d’exécution mon application prend en charge ce comportement.

Je suis tout à fait content de rentrer à travers l’arbre. Ce que je veux éviter, c’est de faire un FindFirst / FindNext pour chaque fichier dans chaque dossier pour voir si certains ont été modifiés dans (disons) le dernier jour – si je peux éviter de le faire pour les dossiers dont l’horodatage n’a pas été modifié dans le dernier jour, vous gagnerez beaucoup de temps.

Vérifiez les fonctions FindFirstChangeNotification et FindNextChangeNotification . Une autre option consiste à utiliser le composant JEDI TJvChangeNotify .

de plus, vous pouvez vérifier ce lien

  • Obtention de notifications de modification de répertoire

Les solutions mises en place jusqu’à présent concernent l’obtention de notifications à mesure qu’elles se produisent et elles fonctionneront bien dans ce but. Si vous voulez regarder dans le passé et voir quand quelque chose a été modifié pour la dernière fois, au lieu de le surveiller en temps réel, cela devient plus difficile. Je pense qu’il n’y a aucun moyen de le faire, sauf en effectuant une recherche récursive dans l’arborescence des dossiers et en vérifiant les horodatages.

EDIT: En réponse au commentaire de l’OP, oui, il ne semble pas y avoir de moyen de configurer FindFirst / FindNext pour ne toucher que les répertoires et non les fichiers. Mais vous pouvez ignorer la vérification des dates sur les fichiers avec ce filtre: (SearchRec.Attr and SysUtils.faDirectory <> 0) . Cela devrait accélérer un peu les choses. Ne cochez pas les dates sur les fichiers. Vous devrez probablement toujours tout parcourir, car l’API Windows ne fournit aucun moyen (que je connaisse) pour interroger uniquement les dossiers et non les fichiers.

J’ai écrit un code à cet effet pour l’un de mes projets. Cela utilise les fonctions de l’API FindFirstChangeNotification et FindNextChangeNotification. Voici le code (j’ai supprimé des parties spécifiques au projet):

 ///  Ali Keshavarz  ///  2010/07/23  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: ssortingng; IsFatal: Boolean) of object; TFolderWatcherThread = class(TThread) private class var TerminationEvent : THandle; private FPath : ssortingng; FPrevModificationTime : TDateTime; FLatestModification : TDateTime; FOnFolderChange : TOnThreadFolderChange; FOnError : TOnThreadError; procedure DoOnFolderChange; procedure DoOnError(const ErrorMsg: ssortingng; IsFatal: Boolean); procedure HandleException(E: Exception); protected procedure Execute; override; public constructor Create(const FolderPath: ssortingng; OnFolderChangeHandler: TOnThreadFolderChange; OnErrorHandler: TOnThreadError); destructor Destroy; override; class procedure PulseTerminationEvent; property Path: ssortingng read FPath; property OnFolderChange: TOnThreadFolderChange read FOnFolderChange write FOnFolderChange; property OnError: TOnThreadError read FOnError write FOnError; end; ///  /// 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. ///  TFolderWatcherThreadList = class(TObjectList) protected procedure Notify(const Value: TFolderWatcherThread; Action: TCollectionNotification); override; end; implementation { TFolderWatcherThread } constructor TFolderWatcherThread.Create(const FolderPath: ssortingng; 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: ssortingng; 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. 

Ceci fournit deux classes; une classe de thread qui surveille un dossier pour les modifications, et si une modification est détectée, elle renverra l’heure de modification actuelle et l’heure de modification précédente via l’événement OnFolderChange. Et une classe de liste pour stocker une liste de threads de surveillance. Cette liste termine automatiquement chaque thread lorsque le thread est supprimé de la liste.

J’espère que ça t’aide.

Vous devriez jeter un oeil à http://help.delphi-jedi.org/item.php?Id=172977 qui est une solution prête à l’emploi. Si vous ne souhaitez pas télécharger et installer la version complète de JVCL (qui est toutefois un excellent morceau de code), vous pouvez consulter le fichier source en ligne – http://jvcl.svn.sourceforge.net/viewvc/jvcl/trunk /jvcl/run/JvChangeNotify.pas?revision=12481&view=markup