Esse artigo faz parte da revista Clube Delphi edição 31. Clique aqui para ler todos os artigos desta edição



Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.
 

Diretórios monitorados

Detectando alterações em arquivos no disco

Existem certas ocasiões onde você necessita saber quando ocorrem mudanças em um determinado diretório, para poder apresentá-las ao usuário, ou mesmo para poder executar alguma ação. Um exemplo disso poderia ser um sistema centralizado de envio de mensagens – todos os usuários da rede criam suas mensagens em um programa padrão, que gera um arquivo num diretório centralizado. Uma outra aplicação monitora este diretório e, quando um novo arquivo é gravado ali, ele despacha a mensagem.

Outro tipo de aplicação que pode fazer uso deste recurso é uma lista que mostra o conteúdo de uma pasta. Digamos que você deseja que esta lista seja atualizada automaticamente quando ocorrem mudanças. Uma maneira de fazer isso seria criar uma thread secundária e ficar monitorando continuamente a pasta, para ver se algo ocorre. A thread teria um código semelhante a:

 

while not Terminated do

  MonitoraDiretorio;

  Application.ProcessMessages;

end;

 

Isto, além de ineficiente, consome muitos recursos da CPU. Seria interessante encontrar outra maneira de fazer isso. O Windows tem as funções FindFirstChangeNotification e FindNextChangeNotification, que monitoram, de forma eficiente, um determinado diretório. Neste artigo, veremos como usar estas funções e criaremos um componente que, quando colocado num formulário, possibilitará a monitoração de qualquer diretório, ativando eventos quando este sofrer alterações.

Funções de notificação

Se você olhar no arquivo de ajuda da API do Windows sobre FindFirstChangeNotification, verá algo como:

 

{ A função FindFirstChangeNotification cria um manipulador

 de notificação de mudança e configura as condições de

 filtro de notificação iniciais. Uma espera sobre o

 manipulador de notificação tem sucesso quando uma mudança

 correspondente às condições de filtro ocorrem no diretório

 ou em subdiretórios.

}
HANDLE FindFirstChangeNotification(
  // ponteiro para no nome do diretório a ser observado

  LPCTSTR lpPathName,
  // monitoração do diretório ou árvore de diretórios

  BOOL bWatchSubtree,
  // condições de filtro a serem observadas

  DWORD dwNotifyFilter
);

 

Isto não parece muito amigável, a coisa não parece ser tão simples assim. Vamos ver inicialmente os parâmetros de FindFirstChangeNotification. O primeiro parâmetro é um PChar contendo o nome do diretório a ser monitorado. O segundo parâmetro é um valor lógico indicando se a monitoração será feita apenas no diretório solicitado ou em todos os subdiretórios deste diretório. O último parâmetro indica a condição de filtro de monitoração. Esta condição é uma combinação or de uma ou mais das seguintes constantes:

FILE_NOTIFY_CHANGE_FILE_NAME – ativa a notificação quando há uma mudança no nome de algum arquivo no diretório, incluindo a criação, exclusão ou mudança de nome de arquivos.

FILE_NOTIFY_CHANGE_DIR_NAME – avisa quando há alguma mudança no nome do diretório atual ou em algum de seus subdiretórios, incluindo a criação ou exclusão de subdiretórios.

FILE_NOTIFY_CHANGE_ATTRIBUTES – avisa quando há mudança de atributos nos arquivos ou subdiretórios.

FILE_NOTIFY_CHANGE_SIZE – ativa a notificação quando há mudança no tamanho dos arquivos. Este aviso só é mostrado quando os dados são efetivamente gravados no disco. Se houver algum tipo de cache, onde os dados são guardados na memória antes de serem gravados fisicamente no disco, a notificação só ocorre após a gravação física.

FILE_NOTIFY_CHANGE_LAST_WRITE – Avisa quando há uma mudança na hora da última gravação de algum arquivo de diretório. O aviso só é feito quando acontece a gravação física dos dados.

FILE_NOTIFY_CHANGE_SECURITY – Avisa quando há alguma modificação nos descritores de segurança do diretório monitorado.

A combinação destas constantes provoca o aviso de quando há alguma modificação no diretório. A função FindFirstChangeNotification retorna um manipulador de evento, que pode ser usado com as funções de espera. Por exemplo, a função WaitForSingleObject espera que um evento seja sinalizado ou um intervalo de tempo tenha ocorrido para retornar. Por exemplo:

 

WaitForSingleObject(Handle, 1000)

 

Este código espera um segundo (mil milissegundos) e retorna, se o evento apontado por Handle não for ativado antes disso. Ela é parecida com a garantia de automóveis: 10 mil quilômetros ou seis meses de garantia – caso você tenha rodado 10 mil km antes dos seis meses, a garantia se esgota, senão ela é válida por seis meses. O uso destas funções combinadas é o seguinte:

var
  Handle: THandle;
begin
  // Cria a notificação
  Handle:= FindFirstChangeNotification(PChar(Diretorio),False,
    FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME);
  if Handle <> INVALID_HANDLE_VALUE then
    if WaitForSingleObject(Handle, 1000) = WAIT_OBJECT_0 then begin
    // houve mudança no diretório

 

A função FindFirstChangeNotification retorna um manipulador válido, ou então INVALID_HANDLE_VALUE, caso haja um erro nos parâmetros da função. Passamos este código de retorno como parâmetro para a função ...

Quer ler esse conteúdo completo? Tenha acesso completo