Monitorando o FileSystem elegantemente

Publicado: 13/08/2008 em Coding

Olá pessoal!!!

Ultimamente ando vendo muitas soluções de problemas baseadas em utilização do FileSystem, principalmente utilizando-se arquivos de texto para comunica aplicações que não tem infraestrutura necessária para uma comunicação elegante entre seus componentes.

Uma coisa que eu vejo é também o desconhecimento de alguns recursos que podem tornar esta tarefa( que já não é a mais elegante possível para trocar informação entre aplicações) mais elegante eheheh

Um bom exemplo disto é verificar quando arquivos são criados em um determinado diretório e assim importar suas informações e utilizá-las no sistema.

Uma prática comum é utilizar um Timer e de tempos em tempos varrer o diretório procurando por novos arquivos…

Minha sugestão para melhorar este trabalho é monitorar o sistema de arquivos utilizando as APIs disponibilizadas pelo sistema operacional, no nosso caso o Windows com sua API Win32 ou o .Net Framework.

.Net Way

No .Net temos a classe FileSystemWatcher que fornece um mecanismo muito elegante baseado em eventos para que saibamos quando alterações acontecem tanto em arquivos quanto em diretórios.

Vejam abaixo o exemplo citado na documentação, ele apresenta um objeto que monitora uma pasta e dispara eventos para alterações nos arquivos .txt. Notem que os eventos podem ser filtrados pelos atributos conhecidos de arquivos e pastas no windows com os NotifyFilters

public class Watcher
{

    public static void Main()
    {
    Run();

    }

    [PermissionSet(SecurityAction.Demand, Name="FullTrust")]
    public static void Run()
    {
        string[] args = System.Environment.GetCommandLineArgs();

        // If a directory is not specified, exit program.
        if(args.Length != 2)
        {
            // Display the proper way to call the program.
            Console.WriteLine("Usage: Watcher.exe (directory)");
            return;
        }

        // Create a new FileSystemWatcher and set its properties.
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = args[1];
        /* Watch for changes in LastAccess and LastWrite times, and
           the renaming of files or directories. */
        watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
           | NotifyFilters.FileName | NotifyFilters.DirectoryName;
        // Only watch text files.
        watcher.Filter = "*.txt";

        // Add event handlers.
        watcher.Changed += new FileSystemEventHandler(OnChanged);
        watcher.Created += new FileSystemEventHandler(OnChanged);
        watcher.Deleted += new FileSystemEventHandler(OnChanged);
        watcher.Renamed += new RenamedEventHandler(OnRenamed);

        // Begin watching.
        watcher.EnableRaisingEvents = true;

        // Wait for the user to quit the program.
        Console.WriteLine("Press ‘q’ to quit the sample.");
        while(Console.Read()!=’q’);
    }

    // Define the event handlers.
    private static void OnChanged(object source, FileSystemEventArgs e)
    {
        // Specify what is done when a file is changed, created, or deleted.
       Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
    }

    private static void OnRenamed(object source, RenamedEventArgs e)
    {
        // Specify what is done when a file is renamed.
        Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
    }
}

O trabalho fica muito bom não?

 

C++ Win32 Way

Se precisarmos utilizar código nativo podemos utilizar a função ReadDirectoryChangesW, que permite que obtenhamos informações sobre alterações no diretório em questão. Esta função é utilizada pelo FileSystemWatcher.
Vejam um exemplo de projeto no CodeProject http://www.codeproject.com/KB/files/directorychangewatcher.aspx

Também existe a função FindFirstNotification que permite que monitoremos os arquivos de maneira elegante utilizando a API Win32.

Abaixo um exemplo retirado do msdn http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

void RefreshDirectory(LPTSTR);
void RefreshTree(LPTSTR);
void WatchDirectory(LPTSTR);

void _tmain(int argc, TCHAR *argv[])
{
    if(argc != 2)
    {
        _tprintf(TEXT("Usage: %s <dir>n"), argv[0]);
        return;
    }

    WatchDirectory(argv[1]);
}

void WatchDirectory(LPTSTR lpDir)
{
   DWORD dwWaitStatus;
   HANDLE dwChangeHandles[2];
   TCHAR lpDrive[4];
   TCHAR lpFile[_MAX_FNAME];
   TCHAR lpExt[_MAX_EXT];

   _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);

   lpDrive[2] = (TCHAR)’\’;
   lpDrive[3] = (TCHAR)”;
// Watch the directory for file creation and deletion. 
   dwChangeHandles[0] = FindFirstChangeNotification(
      lpDir,                          // directory to watch
      FALSE,                          // do not watch subtree
      FILE_NOTIFY_CHANGE_FILE_NAME);  // watch file name changes
   if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
   {
     printf("n ERROR: FindFirstChangeNotification function failed.n");
     ExitProcess(GetLastError());
   }
// Watch the subtree for directory creation and deletion. 
   dwChangeHandles[1] = FindFirstChangeNotification(
      lpDrive,                       // directory to watch
      TRUE,                          // watch the subtree
      FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir name changes
   if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
   {
     printf("n ERROR: FindFirstChangeNotification function failed.n");
     ExitProcess(GetLastError());
   }

// Make a final validation check on our handles.
   if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
   {
     printf("n ERROR: Unexpected NULL from FindFirstChangeNotification.n");
     ExitProcess(GetLastError());
   }

// Change notification is set. Now wait on both notification
// handles and refresh accordingly. 
   while (TRUE)
   {
   // Wait for notification.
      printf("nWaiting for notification…n");

      dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
         FALSE, INFINITE);
      switch (dwWaitStatus)
      {
         case WAIT_OBJECT_0:
         // A file was created, renamed, or deleted in the directory.
         // Refresh this directory and restart the notification.
             RefreshDirectory(lpDir);
             if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
             {
               printf("n ERROR: FindNextChangeNotification function failed.n");
               ExitProcess(GetLastError());
             }
             break;
         case WAIT_OBJECT_0 + 1:
         // A directory was created, renamed, or deleted.
         // Refresh the tree and restart the notification.
             RefreshTree(lpDrive);
             if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
             {
               printf("n ERROR: FindNextChangeNotification function failed.n");
               ExitProcess(GetLastError());
             }
             break;
         case WAIT_TIMEOUT:

         // A time-out occurred. This would happen if some value other
         // than INFINITE is used in the Wait call and no changes occur.
         // In a single-threaded environment, you might not want an
         // INFINITE wait.
            printf("nNo changes in the time-out period.n");
            break;

         default:
            printf("n ERROR: Unhandled dwWaitStatus.n");
            ExitProcess(GetLastError());
            break;
      }
   }
}

void RefreshDirectory(LPTSTR lpDir)
{
   // This is where you might place code to refresh your
   // directory listing, but not the subtree because it
   // would not be necessary.

   _tprintf(TEXT("Directory (%s) changed.n"), lpDir);
}

void RefreshTree(LPTSTR lpDrive)
{
   // This is where you might place code to refresh your
   // directory listing, including the subtree.

   _tprintf(TEXT("Directory tree (%s) changed.n"), lpDrive);
}

Percebem como podemos realmente monitorar um sistema de arquivos de maneira elegante?

Espero que ajude no trabalho, principalmente em situações onde te obrigarem a fazer a comunicação entre sistemas através de arquivos de texto, o que não é muito legal😀 eheheh

Divirtam-se

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s