문제

"최근"수정 된 파일이 포함 된 폴더를 결정해야합니다 (특정 간격 내에서).필자가 포함 된 파일이 수정 될 때마다 폴더 DATESTAMPS가 업데이트되는 것처럼 보이지만이 동작은 트리를 전파하지 않습니다. 즉 수정 된 파일이 들어있는 폴더가 포함 된 폴더의 DATESTAMP가 업데이트되지 않습니다. 이 동작으로 작업 할 수 있지만 플랫폼 / 파일 시스템 / 네트워크 또는 로컬 드라이브 등에 의존하는 것으로 의심합니다. 나는 여전히 내가 할 수있는 곳에서 그것을 이용하기를 원할 것입니다. 그래서 진실을 반환하는 부울 함수가 필요합니다.내 앱을 실행하는 플랫폼 / 디스크 가이 동작을 지원하는 경우

나는 나무를 통해 재발구해서 기쁩니다.내가 피하고 싶은 것은 모든 폴더의 모든 파일에 대해 FindFirst / FindNext를 수행해야합니다. 마지막 날에 수정 된 경우 (Say) DateStamps가 수정되지 않은 폴더에 대해 해결을 피할 수있는 경우를 확인할 수 있습니다.마지막 날에는 많은 시간을 절약 할 것입니다.

올바른 솔루션이 없습니다

다른 팁

FindFirstChangeNotification FindNextChangeNotification 함수 또 다른 옵션은 Jedi 구성 요소를 Jedi Component에서 사용합니다.

덧붙여 링크 가이 링크를 확인할 수 있습니다

지금까지 게시 된 솔루션은 일어날 때 알림을 얻는 것에 관한 것입니다. 그 목적으로 잘 작동합니다.당신이 과거를 들여다 보며, 실제로 그것을 모니터링하는 것과는 대조적으로 마지막으로 바뀌었을 때 뭔가가 바뀌었을 때, 그것은 까다로워집니다.폴더 트리를 재귀 적으로 검색하고 DATESTAMPS를 확인하는 방법이 아닙니다.

편집 : op의 댓글에 대한 응답으로, FindFirst / findNext를 구성하는 방법이 아니라 파일이 아닌 디렉토리 만 히는 방법이있는 것처럼 보이지 않습니다.그러나이 필터가있는 파일의 날짜를 건너 뛸 수 있습니다. (SearchRec.Attr and SysUtils.faDirectory <> 0).그것은 조금 속도를 높여야합니다.파일의 날짜를 전혀 확인하지 마십시오.Windows API가 파일이 아니라 파일이 아닌 폴더에 대해서만 쿼리 할 수있는 방법을 제공하지 않으므로 모든 것을 스캔해야합니다.

나는이 프로젝트 중 하나에 대해이 목적을위한 코드를 작성했습니다.이는 FindFirstChangEnotification 및 FindNextChangEnotification API 함수를 사용합니다. 여기 코드가 있습니다 (일부 프로젝트 특정 부분을 제거) :

/// <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/jvchangenotify.PAS? 개정판= 12481 & View= Markup

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top