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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top