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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top