Быстрое определение того, было ли изменено содержимое папки

StackOverflow https://stackoverflow.com/questions/3313715

Вопрос

Мне нужно определить, какие папки содержат файлы, которые были изменены "недавно" (в течение определенного интервала).Я замечаю, что метки даты папок, похоже, обновляются всякий раз, когда изменяется содержащийся в них файл, но это поведение не распространяется вверх по дереву, т.е.метка даты папки, содержащей папку, содержащую измененный файл, не обновляется.

Я могу работать с таким поведением, но я подозреваю, что это зависит от платформы/файловой системы/сети или локального диска и т.д.Я все равно хотел бы воспользоваться этим там, где мог, поэтому мне нужна логическая функция, возвращающая значение true, если платформа/диск, на котором запущено мое приложение, поддерживает такое поведение.

Я вполне счастлив пройтись по дереву.Чего я хочу избежать, так это необходимости выполнять findFirst / FindNext для каждого файла в каждой папке, чтобы увидеть, были ли какие-либо изменения (скажем) за последний день - если я смогу избежать этого для папок, у которых не изменены метки даты в течение последнего дня, это сэкономит много времени. время.

Нет правильного решения

Другие советы

Проверьте FindFirstChangeNotification и FindNextChangeNotification функции другим вариантом является использование TJvChangeNotify ДЖЕДАЙСКИЙ компонент.

дополнительно вы можете проверить эту ссылку

Решения, которые были опубликованы до сих пор, о получении уведомлений, как они происходят, и они будут хорошо работать для этой цели.Если вы хотите посмотреть в прошлое и посмотреть, когда что-то было в последнее время изменилось, в отличие от мониторинга его в режиме реального времени, то он получает удар.Я думаю, что нет никакого способа сделать это, за исключением рекурсивно в поисках дерева папки и проверяя datestamps.

Редактировать: В ответ на комментарий OP, да, он не похоже, что есть возможность настроить FindFirst / Findnext, чтобы только ударить каталоги, а не файлы.Но вы можете пропустить проверку дат на файлы с помощью этого фильтра: (SearchRec.Attr and SysUtils.faDirectory <> 0).Это должно немного ускорить вещи.Не проверяйте даты в файлах вообще.Вы, вероятно, все равно придется сканировать через все, хотя, поскольку API Windows не предоставляет никакого способа (что я знаю), чтобы только запросил папки, а не файлы.

Я написал код для этой цели для одного из моих проектов.Это использует функции API FindFirstChangenotification и FindNextChangenotification. Вот код (я удалил некоторые специфические части проекта):

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

Это обеспечивает два класса;Класс резьбы, который контролирует папку для изменений, и если обнаружено изменение, он будет возвращать текущее время изменений и предыдущее время изменений через событие на OnFolderChange.И класс списка для хранения списка потоков мониторинга.Этот список автоматически завершает каждую поток, когда поток удален из списка.

Я надеюсь, что это поможет вам.

Вы должны посмотреть на http://help.delphi-jedi.org / item.php? Id= 172977 , который является готовым решением. Если вы не хотите загружать и установить целую JVCL (однако, есть отличный кусок кода;)) Возможно, вы захотите увидеть источник файла онлайн - http://jvcl.svn.sourceforge.net/viewvc/jvcl/trunk/jvcl/run/jvchangeNotify.PAS? Revision= 12481 и AMP; View= Markup

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top