|
Za pomocą klasy FileSystemWatcher, można określić, kiedy i jaka zmiana zaszła w pojedynczym folderze, wszystkich folderach czy na plikach w nich zawartych (oczywiście, można nie oznacza robić, chociażby zapuszczenie FileSystemWatcher na dysku systemowym dałoby olbrzymią liczbę wywołań zdarzeń, w których ponad 98% nie interesowałoby potencjalnego użytkownika, a obsłużenie ich w kodzie nie należałoby to rzeczy, które „tygryski lubią najbardziej”).
Tabela 1 zawiera listę wszystkich zdarzeń obsługiwanych przez klasę FileSystemWatcher. Wynika z niej, że w kodzie aplikacji wykorzystującej komponent FileSystemWatcher, można uzyskiwać informację o utworzeniu, usunięciu, zmienieniu nazwy, czy zmodyfikowaniu (w dowolny sposób) plików/katalogów, co w cale nie oznacza, że aby użyć tej klasy należy obsłużyć każde zdarzenie. Równie dobrze można obsłużyć tylko jedno z nich, jak i wszystkie, wszystko zależy od programisty.
Zdarzenie generowane |
Opis zdarzenia |
Changed |
Uruchamiane, gdy plikowi lub katalogowi zostanie zmieniona jedna z własności:
|
Created |
Uruchamiane za każdym razem, gdy zostanie utworzony plik lub folder. |
Deleted |
Uruchamiane za każdym razem, gdy zostanie usunięty plik lub folder. |
Renamed |
Uruchamiane za każdym razem, gdy zostanie zmieniona nazwa pliku lub folderu. |
Tabela 1 Zdarzenia generowane przez FileSystemWatcher
Najlepiej zaobserwować sposób działania klasy FileSystemWatcher przez praktykę, w tym celu należy uruchomić Visual Studio .NET i utworzyć nowy projekt aplikacji windowsowej (tutaj wybór jest dowolny równie dobrze można korzystać z klasy FileSystemWatcher w C# jak i VB.NET). Następnie dodać do Form1 komponent Button i TextBox tak jak to pokazano na rysunku 1.

Rys. 1 Główne okno aplikacji
Następnie na Form1 należy dodać komponent FileSystemWatcher, który znajduje się w zakładce Components w ToolBoxie. Ze względu na to, że komponent jest niewidoczny, jego istnienie w aplikacji można zaobserwować w kodzie lub w oknie projektowania Form1 w dolnym pasku zwanym tray.
Kolejnym krokiem jest dodanie deklaracji używania/zaimportowania (w zależności od języka) przestrzeni nazw System.IO.
using System.IO;
Kod 1 Kod Dla C#
Imports System.IO
Kod 1 Kod dla VB.NET
By to wszystko ze sobą zgrać do zdarzenia Click przycisku umieszczonego na Form1 należy dodać następujący kod:
private void cmdMonitor_Click(object sender, System.EventArgs e) { if(Directory.Exists(txtDir.Text)) { fswMonitoring.Path = txtDir.Text; fswMonitoring.IncludeSubdirectories = true; fswMonitoring.EnableRaisingEvents = true; fswMonitoring.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName; fswMonitoring.Filter = "*.*"; fswMonitoring.Renamed += new RenamedEventHandler(OnFileRenamed); } else { MessageBox.Show("Directory does not exist. Please type a nie path", "Directory error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
Kod 2 Zdarzenie Click przycisku Monitor (kod w C#)
Private Sub cmdMonitor_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdMonitor.Click If Directory.Exists(txtDir.Text) Then fswMonitoring.Path = txtDir.Text fswMonitoring.IncludeSubdirectories = True fswMonitoring.EnableRaisingEvents = True fswMonitoring.NotifyFilter = (NotifyFilters.FileName Or NotifyFilters.DirectoryName) fswMonitoring.Filter = "*.*" AddHandler fswMonitoring.Renamed, AddressOf OnFileRenamed Else MessageBox.Show("Directory does not exist. Please type a nie path", "Directory error", MessageBoxButtons.OK, MessageBoxIcon.Error) End If End Sub
Kod 2 Zdarzenie Click przycisku Monitor (kod w VB.NET)
Klasa FileSystemWatcher może monitorować pliki lokalnie jak i zdalne oraz na dyskach sieciowych na dowolnym systemie klasy NT (w tym Windows XP). Ze względów oczywistych monitorowanie plików na nośnikach trwałych jak CD-ROM czy DVD-ROM nie ma sensu, gdyż nie zachodzą na nich zmiany. Tabela 2 zawiera atrybuty, które można ustawić w klasie FileSystemWatcher.
W przykładzie, który został stworzony w tym artykule, pod zdarzeniem Click przycisku zostaje ustawiona (podana przez użytkownika w polu TextBox) ścieżka Path, która może, ale nie musi być poprawną ścieżką do katalogu. W tym celu następuje sprawdzenie czy dana ścieżka istnieje w systemie (Direktory.Exists), jeżeli tak następuje ustawienie kolejnych atrybutów. Ze względu na pokazanie możliwości klasy FileSystemWatcher, atrybut IncludeSubdirectories został ustawiony na True, by pokazać, iż można monitorować także podkatalogi i pliki w nich zawarte niż tylko podany katalog. Kolejnym ustawionym atrybutem jest EnabledRaisingEvents (ustawiony na True), który mówi komponentowi, FileSystemWatcher, aby wywoływał zdarzenia mu przypisane za każdym razem, gdy zostanie zmieniony monitorowany plik lub katalog. Za każdym razem, gdy FileSystemWatcher wykryje zajście zmiany w obserwowanej strukturze plików, wywoła odpowiednie zdarzenie, jeżeli wartość EnabledRaisingEvents jest ustawiona na True.
Atrybut |
Opis |
EnabledRaisingEvents |
Flaga określająca czy kontrolka FileSystemWatcher jest aktywna (True) lub nieaktywna (False). |
Filter |
Atrybut określający maskę monitorowanych plików. Standardowo maska ustawiona jest na wszystkie pliki (*.*) |
IncludeSubdirectories |
Flaga określająca czy kontrolka FileSystemWatcher ma monitorować (True) podkatalogi, czy nie (False). |
SynchronizinObject |
Atrybut synchronizuje monitorowane zdarzenia do danego obiektu na np.: formularzu (np.: zdarzenie Changed będzie dopiero wywoływane jak zostanie kliknięty przycisk Check). |
NotifyFilter |
Flaga określająca, jakie zdarzenia mają być monitorowane. Można monitorować następujące zdarzenia:
FileName
DirectoryName
Attribute
Size
LastWrite
LastAccess
CreationTime
Security
|
Path |
Określa ścieżkę na dysku twardym, jaka ma być monitorowana. |
Tabela 2 Atrybuty komponentu FileSystemWatcher
Atrybut NotifyFilter umożliwia określenie typów zdarzeń, które mają być monitorowane przez FileSystemWatcher. W kodzie do artykuły monitorowane są jedynie zdarzenia odpowiedzialne za zmianę nazwy pliku lub katalogu. Typy zdarzeń można łączyć ze sobą za pomocą operacji boolowskiej lub (Or czy | w zależności od języka), by móc określić, które zdarzenia mają być monitorowane i kiedy. Tabela 3 pokazuje wszystkie możliwe typy zdarzeń, które mogą być monitorowane. Na końcu zostaje ustawiony atrybut Filter wartością „*.*”, która korzysta z znaków wieloznacznych (ang. wildcard), co w tym przypadku oznacza „wszystkie pliki z dowolnym rozszerzeniem”. Równie dobrze, można tutaj podać wartość „*.DOC” oznaczającą wszystkie pliki o rozszerzeniu DOC czy „CodeGuru.*” oznaczające „wszystkie pliki o nazwie CodeGuru z dowolnym rozszerzeniem”.
Typ zdarzenia |
Opis |
Attributes |
Wywołuje zdarzenie, kiedy atrybut pliku zostanie zmieniony. |
CreationTime |
Wywołuje zdarzenie, kiedy plik lub katalog zostanie utworzony. |
DirectoryName |
Wywołuje zdarzenie, kiedy zostanie zmieniona nazwa katalogu. |
FileName |
Wywołuje zdarzenie, kiedy zostanie zmieniona nazwa pliku. |
LastAccess |
Wywołuje zdarzenie, kiedy zostanie zmieniona data ostatniego otwarcia pliku lub katalogu. |
LastWrite |
Wywołuje zdarzenie, kiedy zostanie zmieniona data ostatniego zapisania pliku lub zapisania do katalogu. |
Security |
Wywołuje zdarzenie, kiedy zostaną zmienione prawda dostępu do pliku lub katalogu. |
Size |
Wywołuje zdarzenie, kiedy rozmiar pliku lub katalogu ulegnie zmianie. |
Tabela 3 Zdarzenia, które mogą być monitorowane
Po ustawieniu wszystkich atrybutów FileSystemWatcher, zostanie dodany kod mówiący aplikacji, co ma zrobić, gdy zajdzie dane zdarzenie (jak ma je obsłużyć, co ma je obsłużyć, jaka funkcja, metoda). W tym celu zostaje umieszczona linijka:
fswMonitoring.Renamed += new RenamedEventHandler(OnFileRenamed);
Kod 3 Event handler C#
AddHandler fswMonitoring.Renamed, AddressOf OnFileRenamed
Kod 3 Event handler VB.NET
Za każdym razem, gdy ma zostać obsłużone dane zdarzenie w komponencie FileSystemWatcher, należy dodać odpowiedni kod, który obsłuży je w aplikacji. Najlepszym przykładem jest aplikacja utworzona w ramach artykułu. Wywołuje ona MessageBox za każdym razem, gdy nastąpi zmiana nazwy pliku i/lub katalogu, który jest monitorowany. W tym celu został dodany event handler wywołujący procedurę OnFileRenamed. Przy dodawaniu event handlerów do danych zdarzeń należy w parametrze przekazać nazwę procedury, która ma obsłużyć, zainstaniałe zdarzenie.
private static void OnFileRenamed(object source, RenamedEventArgs e) { MessageBox.Show("A " + e.OldName + " was renamed to " + e.Name, "OnFileRenamed", MessageBoxButtons.OK, MessageBoxIcon.Information); }
Kod 4 Kod procedury OnFileRenamed (Kod w C#)
Private Shared Sub OnFileRenamed(ByVal source As Object, ByVal e As RenamedEventArgs) MessageBox.Show("A " & e.OldName & " was renamed to " & e.Name, "OnFileRenamed", MessageBoxButtons.OK, MessageBoxIcon.Information) End Sub
Kod 4 Kod procedury OnFileRenamed (Kod w VB.NET)
Podsumowanie
FileSystemWatcher jest prostym w obsłudze komponentem umożliwiającym śledzenie działań wykonywanych na poszczególnych plikach i katalogach w podanej ścieżce. Może on okazać się bardzo przydatny przy pomniejszych projektach, gdzie SourceControl nie jest wymagany, jednak wiedza o przeprowadzonych zmianach czasami może być przydatna. Może też znaleźć zapotrzebowanie w aplikacjach, które monitorują jakiś katalog, by jak tylko wpadnie do niego plik, pobrać go i przetworzyć informacje w nim zawarte – takim przykładem może być chociażby, SMS, który pewne ustawienia zasysa z jednego katalogu. Wystarczy tam wgrać plik, a zaraz po tym plik jest przez SMS przetwarzany.
Warto także zapoznać się z usługami (Services), gdyż w połączeniu z FileSystemWatcher, mogą one być bardzo przydatne, przykładem takim jest usługa monitorująca pliki w danej ścieżce. Dzięki wykorzystaniu własności usług, użytkownik nawet nie musi wiedzieć o tym, iż jest ona włączona, co jest dodatkowym plusem.
Informacja o załączonym kodzie
Do artykułu został załączony kod w C# i w VB.NET, który oprogramowuje resztę dostępnych zdarzeń w klasie FileSystemWatcher. Warto się jest mu przejrzeć, zawsze można kod przekopiować do swoich projektów zamiast pisać go na nowo.
Kod dodatkowych zdarzeń
// Dodanie event handlerow do cmdMonitor_Click fswMonitoring.Created += new FileSystemEventHandler(OnFileCreated); fswMonitoring.Changed += new FileSystemEventHandler(OnFileChanged); fswMonitoring.Deleted += new FileSystemEventHandler(OnFileDeleted); //... private static void OnFileCreated(object source, FileSystemEventArgs e) { MessageBox.Show("A " + e.Name + " was created", "OnFileCreated", MessageBoxButtons.OK, MessageBoxIcon.Information); } private static void OnFileChanged(object source, FileSystemEventArgs e) { MessageBox.Show("Change detected on file in " + e.FullPath , "OnFileChanged", MessageBoxButtons.OK, MessageBoxIcon.Information); } private static void OnFileDeleted(object source, FileSystemEventArgs e) { MessageBox.Show("A " + e.Name + " was deleted", "OnFileDeleted", MessageBoxButtons.OK, MessageBoxIcon.Information); }
Kod 5 Pozostałe zdarzenia (Kod w C#)
´ Dodanie event handlerow do cmdMonitor_Click AddHandler fswMonitoring.Created, AddressOf OnFileCreated AddHandler fswMonitoring.Changed, AddressOf OnFileChanged AddHandler fswMonitoring.Deleted, AddressOf OnFileDeleted ´... Private Shared Sub OnFileCreated(ByVal source As Object, ByVal e As FileSystemEventArgs) MessageBox.Show("A " & e.Name & " was created", "OnFileCreated", MessageBoxButtons.OK, MessageBoxIcon.Information) End Sub Private Shared Sub OnFileChanged(ByVal source As Object, ByVal e As FileSystemEventArgs) MessageBox.Show("Change detected on file in " & e.FullPath, "OnFileChanged", MessageBoxButtons.OK, MessageBoxIcon.Information) End Sub Private Shared Sub OnFileDeleted(ByVal source As Object, ByVal e As FileSystemEventArgs) MessageBox.Show("A " & e.Name & " was deleted", "OnFileDeleted", MessageBoxButtons.OK, MessageBoxIcon.Information) End Sub
Kod 5 Pozostałe zdarzenia (Kod w VB.NET)
|