Determinazione rapida se è stato modificato un contenuto di cartelle
-
27-09-2020 - |
Domanda
Devo determinare quali cartelle contengono file che sono stati modificati "di recente" (entro un determinato intervallo).Ho notato che i dati della cartella sembrano aggiornati ogni volta che un file contenuto viene modificato, ma questo comportamento non propaga l'albero, ovvero il DataStamp della cartella contenente la cartella che contiene il file modificato non viene aggiornato. Posso lavorare con questo comportamento, ma io sospetto che dipenda dalla piattaforma / system / rete o un'unità locale, ecc. Mi piacerebbe ancora approfittarlo dove potrei, quindi ho bisogno di una funzione booleana per tornare veroSe la piattaforma / disco che esegue la mia app supporta questo comportamento.
Sono abbastanza felice di ricurserare attraverso l'albero.Quello che voglio evitare di evitare di trovare un findfirst / findnext per ogni file in ogni cartella per vedere se qualcuno è stato modificato in (Dì) l'ultimo giorno - se posso evitare di farlo per le cartelle che non hanno modificato i loro data-esterampNell'ultimo giorno farà risparmiare un grande periodo di tempo.
Nessuna soluzione corretta
Altri suggerimenti
Controllare il FindFirstChangeNotification
e FindNextChangeNotification
funzioni
Un'altra opzione è utilizzare il TJvChangeNotify
JEDI Component.
IDENIONAMENTE È possibile controllare questo collegamento
Le soluzioni che sono state pubblicate finora stanno per ottenere notifiche come accadono e funzionano bene per questo scopo.Se vuoi guardare nel passato e vedi quando qualcosa è stato cambiato per l'ultima volta, al contrario di monitorarlo in tempo reale, allora diventa Tricker.Penso che non sia il modo di farlo se non per la ricerca ricorsivamente attraverso l'albero delle cartelle e controllando i datastamps.
Modifica: In risposta al commento dell'OP, sì, non sembra che ci sia un modo per configurare FindFirst / FindNext solo per colpire le directory e non i file.Ma è possibile saltare il controllo delle date sui file con questo filtro: (SearchRec.Attr and SysUtils.faDirectory <> 0)
.Questo dovrebbe accelerare un po 'le cose.Non controllare le date sui file.Probabilmente dovrai ancora eseguire la scansione di tutto, però, poiché l'API di Windows non fornisce in alcun modo (che conosco) solo la query per le cartelle e non i file.
Ho scritto un codice per questo scopo per uno dei miei progetti.Questo utilizza FindFirstCagenGenotification e FindNextChangenotification Funzioni API. Ecco il codice (ho rimosso alcune porzioni specifiche del progetto):
/// <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.
.
Questo fornisce due classi;Una classe di thread che monitora una cartella per le modifiche e se viene rilevata una modifica, restituirà il tempo di modifica corrente e il tempo di modifica precedente tramite evento OnFolderChange.E una classe di elenco per la memorizzazione di un elenco di thread di monitoraggio.Questa lista termina automaticamente ciascun thread quando il thread viene rimosso dall'elenco.
Spero che ti aiuti.
Dovresti dare un'occhiata a http://help.delphi-jedi.org / item.php? ID= 172977 che è una soluzione pronta. Se non vuoi scaricare e installare intero JVCL (che è comunque un ottimo codice;)) potrebbe voler vedere la fonte del file online - http://jvcl.svn.sourceforge.net/viewvc/jvcl/trunk/jvcl/run/jvchangenotify.pas? revisione= 12481 e amp; Visualizza= markup