Rapidamente determinar se uma pasta de conteúdo foi modificado
-
27-09-2020 - |
Pergunta
Eu preciso determinar quais as pastas que contêm os arquivos que foram modificados "recentemente" (dentro de um certo intervalo).Eu percebo que a pasta datestamps parecem ficar atualizado sempre que uma contidas arquivo é modificado, mas este comportamento não propagar até a árvore, i.é.o datestamp da pasta que contém a pasta que contém o arquivo modificado de não ser actualizado.
Eu posso trabalhar com esse comportamento, mas eu suspeito que ele depende de plataforma/sistema de arquivos/rede ou unidade de disco local, etc.Eu ainda gostaria de tirar partido do mesmo, onde eu pudesse, então eu preciso de uma função booleana de retornar true se a plataforma/disco executar meu aplicativo suporta este tipo de comportamento.
Eu estou muito feliz de recurse através da árvore.O que eu quero evitar, é ter que fazer um FindFirst/FindNext para todos os arquivos em cada pasta para ver se algum tiver sido modificado em (digamos) o último dia, se eu pode evitar fazer para que as pastas que não têm o seu datestamps modificado no último dia, vai economizar uma grande quantidade de tempo.
Nenhuma solução correta
Outras dicas
Verifique o FindFirstChangeNotification
e FindNextChangeNotification
funções
outra opção é usar o TJvChangeNotify
JEDI componente.
addionally você pode consultar este link
As soluções que foram postadas até agora são sobre a obtenção de notificações à medida que acontecem, e elas funcionam bem para esse fim.Se você quer olhar para o passado e ver quando algo foi alterado pela última vez, ao contrário de monitorá-lo em tempo real, então ele fica enganoso.Eu acho que não há como fazer isso, exceto por pesquisa recursivamente através da árvore de pastas e verificar dados de dados.
edit: Em resposta ao comentário do OP, sim, não parece que há qualquer maneira de configurar o FindFirst / FindNext apenas pressione apenas diretórios e não.Mas você pode pular verificando as datas nos arquivos com este filtro: (SearchRec.Attr and SysUtils.faDirectory <> 0)
.Isso deve acelerar as coisas um pouco.Não verifique as datas nos arquivos.Você provavelmente ainda terá que digitalizar através de tudo, já que a API do Windows não fornece nenhuma maneira (que eu saiba) apenas consulta para pastas e não arquivos.
Eu escrevi um código para este propósito que um dos meus projetos.Este usa FindFirstChangeNotification e FindNextChangeNotification funções da API.Aqui está o código (eu removi algum projeto específico porções):
/// <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.
Isso fornece duas classes;um segmento de classe que monitoriza uma pasta para mudanças, e se for detectada uma alteração, ele vai voltar a atual mudança do tempo e a alteração anterior o tempo, através de OnFolderChange evento.E uma lista de classes para armazenar uma lista de monitoração de threads.Esta lista termina, cada thread automaticamente quando a thread é removido da lista.
Espero que ajude você.
Você deve dar uma olhada em http://help.delphi-jedi.org / item.fp? ID= 172977 Qual é uma solução pronta. Se você não quiser baixar e instalar JVCl inteiro (o que é, no entanto, um grande pedaço de código;)) Você pode querer ver a fonte de arquivo on-line - http://jvcl.svn.sourceforge.net/viewvc/jvcl/jvchangenotify.PAS? Revisão= 12481 & ver= marcação