Minha primeira ideia para monitorar uma pasta no Windows foi colocar um temporizador (TTimer do Delphi ou C++ Builder). Dado um intervalo de tempo, a pasta seria varrida para determinar se havia arquivo novo a ser importado. Deparei, então, com a questão "Qual intervalo de tempo é apropriado ?". Se o intervalo for muito curto, o programa pode consumir demais os recursos do computador sem necessidade; se o tempo for muito longo, pode haver demora excessiva para a importação e, como o arquivo gerado tem ligação com faturamento do Cliente ...
Pesquisando um pouco mais, encontrei algumas funções de gerenciamento de pastas da API do Windows que ajudaram a abandonar o temporizador para resolver o problema. A função base é a FindFirstChangeNotification. A ideia dessa função é simplesmente criar um vínculo do seu programa com uma pasta do Windows de forma que você é notificado sempre que alguma mudança ocorrer nesta pasta. O código abaixo pede ao Windows que notifique mudanças na pasta "C:\temp":
HWND _WaitHandle = FindFirstChangeNotification ("C:\\TEMP", false, FILE_NOTIFY_CHANGE_FILE_NAME);
O primeiro parâmetro é o nome da pasta a ser monitorada - se tiver que monitorar mais pastas, terá que chamar a função uma vez para cada pasta. O segundo parâmetro indica se quero monitorar também as pastas que estão dentro daquela informada no primeiro parâmetro. Informei false pois não quero monitorar toda a árvore de pastas. O último parâmetro informa que tipo de mudança quero monitorar. O valor FILE_NOTIFY_CHANGE_FILE_NAME faz com que o programa seja notificado sempre que ocorrer qualquer mudança em nome de arquivo na pasta monitorada. Atenção apenas para um detalhe: "mudança de nome", aqui, inclui a criação de novos arquivos, a cópia de arquivos e a remoção de arquivos. Dê uma olhada na documentação da função para ver as outras possibilidades. No fim, a função retorna um Handle que será usado para responder ao evento.
Como é que o programa é notificado a respeito da mudança? Aqui entra uma diferença básica em relação ao princípio usado por eventos no Delphi/C++ Builder: o programa para de executar e fica em "espera" até que uma mudança seja notificada ou até que um tempo estipulado se esgote. Como no meu caso o programa faz outras coisas e não pode ficar esperando, criei uma Thread separada apenas para monitorar:
while (! Terminated)
{
VerificaPasta();
ret = WaitForSingleObject (_WaitHandle, 30000);
if (ret == WAIT_OBJECT_0 && (! Terminated))
{
VerificaPasta();
FindNextChangeNotification (_WaitHandle);
}
}
{
VerificaPasta();
ret = WaitForSingleObject (_WaitHandle, 30000);
if (ret == WAIT_OBJECT_0 && (! Terminated))
{
VerificaPasta();
FindNextChangeNotification (_WaitHandle);
}
}
A função de sincronização WaitForSingleObject é que faz o programa aguardar até que o handle fornecido receba uma notificação ou que o tempo requisitado expire - no exemplo, esse tempo é de 30 segundos. Se esta função retornar o valor WAIT_OBJECT_0, significa que a espera terminou por causa de uma notificação de mudança (e não por timeout).
E como eu sei que a notificação foi motivada pela criação de um novo arquivo ou se um arquivo foi removido ou se simplesmente ele foi renomeado? É preciso vasculhar a pasta para determinar pois o evento em si não dá essa informação ... É o que faz a minha função VerificaPasta no exemplo acima.
Uma vez que a função de espera sai por causa de uma notificação, o programa deixa de receber novas notificações de mudança. Se quiser continuar a recebê-las, é preciso registrar novamente, dessa vez através de uma chamada à função FindNextChangeNotification, isto é, "aguarde a próxima notificação". Veja no exemplo que usei o mesmo Handle usado na chamada à função FindFirstChangeNotification.
Quando não quiser mais receber notificações, o handle tem que ser encerrado:
FindCloseChangeNotification (_WaitHandle);
Nenhum comentário :
Postar um comentário
OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.
Observação: somente um membro deste blog pode postar um comentário.