Pregunta

Necesito determinar qué carpetas contienen archivos que se han modificado "recientemente" (dentro de un intervalo determinado).Me doy cuenta de que la carpeta Datascamps parece actualizarse cada vez que se modifique un archivo contenido, pero este comportamiento no se propaga al árbol, es decir, el DataStamp de la carpeta que contiene la carpeta que contiene el archivo modificado no se actualiza.

Puedo trabajar con este comportamiento, pero sospecho que depende de la plataforma / sistema de archivos / red o la unidad local, etc. Aún me gustaría aprovecharla donde podría, así que necesito una función booleana para devolverSi la plataforma / disco que ejecuta mi aplicación admite este comportamiento.

Estoy muy feliz de recurrir a través del árbol.Lo que quiero evitar es tener que hacer un FindFirst / FindNext para cada archivo en cada carpeta para ver si se ha modificado en (di) el último día, si puedo evitar hacerlo para carpetas que no tienen sus datos de datos modificados.Dentro del último día ahorrará mucho tiempo.

No hay solución correcta

Otros consejos

Verifique el FindFirstChangeNotification y FindNextChangeNotification Funciones Otra opción es usar la TJvChangeNotify Componente Jedi.

Amás, puede verificar este enlace

Las soluciones que se han publicado hasta ahora son sobre la obtención de notificaciones a medida que ocurren, y trabajarán bien para ese propósito.Si quieres mirar en el pasado y ver cuando se cambió algo, en lugar de monitorearlo en tiempo real, entonces se engaña.Creo que no hay forma de hacer eso, excepto en la búsqueda recursivamente a través del árbol de carpetas y revisar los Datascamps.

Editar: En respuesta al comentario de OP, sí, no parece que haya ninguna manera de configurar FindFirst / FindNext para ir solo a los directorios y no los archivos.Pero puede omitir la comprobación de las fechas en los archivos con este filtro: (SearchRec.Attr and SysUtils.faDirectory <> 0).Eso debería acelerar un poco a las cosas.No revise las fechas en los archivos en absoluto.Sin embargo, probablemente tenga que escanear todo, ya que la API de Windows no proporciona ninguna forma (que conozco) solo consulta para las carpetas y no los archivos.

Escribí un código para este propósito para uno de mis proyectos.Esto utiliza FindFirstchangenotification y FindNextCangeNotification API Funciones. Aquí está el código (quito algunas porciones específicas del proyecto):

/// <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.

Esto proporciona dos clases;Una clase de hilo que monitorea una carpeta para cambios, y si se detecta un cambio, devolverá el tiempo de cambio actual y el tiempo de cambio anterior a través del evento OnFolderchange.Y una clase de lista para almacenar una lista de hilos de monitoreo.Esta lista termina cada solo hilo automáticamente cuando el hilo se elimina de la lista.

Espero que te ayude.

Debe echar un vistazo a http://help.delphi-jedi.org / item.php? ID= 172977 que es una solución lista. Si no desea descargar e instalar todo JVCL (que es sin embargo, una gran pieza de código;)) Es posible que desee ver la fuente de archivo en línea, http://jvcl.svn.sourceforge.net/viewvc/jvcl/trunk/jvcl/run/jvchangenotify.pas? Revisión= 12481 & Ver= Markup

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top