Rapidement déterminer si un dossier contenu ont été modifiés
-
27-09-2020 - |
Question
J'ai besoin de déterminer les dossiers contiennent des fichiers qui ont été modifiés "récemment" (à l'intérieur d'un certain intervalle).J'ai remarqué que le dossier de timbres à date semblent avoir mis à jour chaque fois qu'un fichier est modifié, mais ce comportement ne se propagent pas en haut de l'arborescence, c'est à direl'horodatage du dossier contenant le dossier qui contient le fichier modifié n'est pas mis à jour.
Je peux travailler avec ce comportement, mais je suppose que cela dépend de plate-forme/système de fichiers/réseau ou le disque local, etc.Je voudrais encore profiter de celui-ci où j'ai pu, j'ai donc besoin d'une fonction booléenne à retourner true si la plate-forme/disque exécution de mon application prend en charge ce comportement.
Je suis très heureux de le répéter au travers de l'arbre.Ce que je veux éviter, c'est d'avoir à faire un FindFirst/FindNext pour chaque fichier dans chaque dossier pour voir si tout a été modifié (dire) le dernier jour - si je peux éviter de le faire que pour les dossiers qui n'ont pas de timbres à date modifiée dans le dernier jour, il permettra d'économiser beaucoup de temps.
Pas de solution correcte
Autres conseils
De vérifier la FindFirstChangeNotification
et FindNextChangeNotification
fonctions
une autre option est d'utiliser la TJvChangeNotify
JEDI composant.
de plus, vous pouvez consulter ce lien
Les solutions qui ont été publiés jusqu'à présent sont sur l'obtention des notifications dès qu'ils se produisent, et ils fonctionnent bien pour cette fin.Si vous voulez regarder dans le passé et de voir quand quelque chose a été modifié, par opposition à la surveillance en temps réel, il devient alors plus difficile.Je pense qu'il n'y a aucun moyen de le faire que de manière récursive par la recherche par le biais de l'arborescence de dossiers et la vérification des timbres à date.
EDIT: En réponse à l'OP commentaire, oui, il ne ressemble pas il y a moyen de configurer FindFirst/FindNext à seulement frapper les répertoires et les fichiers.Mais vous pouvez pas vérifier la date sur les fichiers de ce filtre: (SearchRec.Attr and SysUtils.faDirectory <> 0)
.Qui devrait accélérer les choses un peu.Ne pas vérifier les dates sur les fichiers.Vous aurez probablement encore besoin de numériser à travers tout, mais, depuis l'API Windows ne fournit pas de toute façon (que je connais) à la seule requête pour les dossiers et les fichiers.
J'ai écrit un code à cette fin pour l'un de mes projets.Cela utilise des fonctions API de FindFirstChangenotification et FindNextChangenotification. Voici le code (j'ai supprimé certaines portions spécifiques au projet):
/// <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.
Ceci fournit deux classes;Une classe de thread qui surveille un dossier pour les modifications et si une modification est détectée, elle retournera le temps de changement en cours et le temps de modification précédent via l'événement OnfolderChange.Et une classe de liste pour stocker une liste de threads de surveillance.Cette liste termine chaque propre thread automatiquement lorsque le thread est retiré de la liste.
J'espère que ça vous aide.
Vous devriez consulter http://help.delphi-jedi.org / item.php? id= 172977 qui est une solution prête. Si vous ne voulez pas télécharger et installer entier JVCL (qui est cependant un excellent code de code;)) Vous pouvez voir la source de fichiers en ligne - http://jvcl.svn.sourceforge.net/viewvc/jvcl/trunk/jvcl/run/jvchangénotify.pas? révision= 12481 & vue= marquage