폴더 내용이 수정되었는지를 신속하게 결정합니다
-
27-09-2020 - |
문제
"최근"수정 된 파일이 포함 된 폴더를 결정해야합니다 (특정 간격 내에서).필자가 포함 된 파일이 수정 될 때마다 폴더 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