FileSystemWatcher vs odpytywanie w poszukiwaniu zmian plików

152

Muszę skonfigurować aplikację, która śledzi pliki tworzone w katalogu, zarówno lokalnie, jak i na dysku sieciowym.

Czy FileSystemWatchernajlepszym rozwiązaniem byłoby odpytywanie czasomierza lub. W przeszłości stosowałem obie metody, ale nie na szeroką skalę.

Jakie problemy (wydajność, niezawodność itp.) Występują w przypadku obu metod?

Jon Tackabury
źródło
3
FileSystemWatcher jest nieszczelną abstrakcją i nie można na niej polegać w niczym innym, jak tylko w najbardziej podstawowych przypadkach. Zobacz tutaj: stackoverflow.com/a/22768610/129130
Stein Åsmul
1
Chcesz dodać odsyłacz do tej odpowiedzi Raymonda Chena (eksperta firmy Microsoft) na temat niezawodności FileSystemWatcher . I jego blog: The Old New Thing (na przykład wyszukaj FileSystemWatcher).
Stein Åsmul

Odpowiedzi:

105

Widziałem awarię obserwatora systemu plików w środowiskach produkcyjnych i testowych. Teraz uważam to za wygodę, ale nie uważam tego za wiarygodne. Mój wzorzec polegał na tym, że obserwowałem zmiany za pomocą obserwatora systemu plików, ale od czasu do czasu sondowałem, aby wykryć brakujące zmiany w plikach.

Edycja: jeśli masz interfejs użytkownika, możesz również dać użytkownikowi możliwość „odświeżania” zmian zamiast odpytywania. Połączyłbym to z obserwatorem systemu plików.

Jason Jackson
źródło
11
Ja też widziałem, jak spadają. Rozwiązaniem, którego użyliśmy, jest zawinięcie naszej własnej klasy, gdzie klasa opakowująca RÓWNIEŻ używa licznika czasu do sprawdzania, czy obserwator nadal działa.
Joel Coehoorn
Robimy coś podobnego - po przetworzeniu pliku przekazanego do zdarzenia FileCreated, przed zwróceniem ręcznie sprawdzamy, czy nie ma innych nowych plików. Wydaje się, że łagodzi to wszelkie problemy występujące podczas jednoczesnego przesyłania wielu plików.
John Sibly,
4
Wydaje mi się, że przetestowaliśmy go w XP i Server 2003 w lokalnym katalogu i udziale plików i mieliśmy komputery XP w terenie. Mieliśmy problemy z lokalnym katalogiem i udostępnianiem plików. Jedną z prawdopodobnych przyczyn, które wymyśliliśmy, było skopiowanie / utworzenie wielu plików w katalogu w krótkim czasie.
Jason Jackson
5
Nie jest zbyt konstruktywne ani profesjonalne stwierdzenie „pewnego dnia widziałem ducha”. Wygląda na to, że ludzie w tym wątku, wspominając o dokumencie msdn o przepełnieniach bufora, których nie można wyświetlić na stronie, mogą wyjaśnić twoje problemy. Czy próbowałeś zastosować podejście Brenta?
v.oddou,
4
Właśnie kupiłem czujnik gazu na Amazon i zdziwiło mnie, ile osób powiedziało, że nie działa, kiedy oczywiście nie skalibrowali go poprawnie lub nawet nie wiedzieli o kalibracji ... FileSystemWatcher zna ograniczenia związane z dużym ruchem z rozmiar bufora. Prawie gwarantowane, że to powód jego „niepowodzenia”. Można to łatwo wyjaśnić w dokumentacji i istnieją obejścia, które zapewniają bardzo niezawodne działanie (jak przedstawiono poniżej). To nie jest dobra odpowiedź, aby po prostu powiedzieć „błąd, coś nie zadziałało raz, nie wiem dlaczego… nikt nie powinien na tym polegać”.
u8it
60

Największym problemem, jaki miałem, są brakujące pliki, gdy bufor się zapełni. Łatwe do naprawienia - po prostu zwiększ bufor. Pamiętaj, że zawiera nazwy plików i zdarzenia, więc zwiększ go do oczekiwanej liczby plików (metoda prób i błędów). Używa pamięci, której nie można stronicować, więc może zmusić inne procesy do stronicowania, jeśli pamięć się wyczerpie.

Oto artykuł MSDN dotyczący bufora: Właściwość FileSystemWatcher .. ::. InternalBufferSize

Według MSDN:

Zwiększenie rozmiaru bufora jest kosztowne, ponieważ pochodzi z pamięci niestronicowanej, której nie można zamienić na dysk, dlatego należy utrzymywać jak najmniejszy bufor. Aby uniknąć przepełnienia buforu, użyj właściwości NotifyFilter i IncludeSubdirectories w celu odfiltrowania niechcianych powiadomień o zmianach.

Używamy 16 MB ze względu na spodziewaną dużą partię jednorazowo. Działa dobrze i nigdy nie pomija pliku.

Czytamy również wszystkie pliki przed rozpoczęciem przetwarzania choćby jednego ... pobieramy nazwy plików z bezpiecznej pamięci podręcznej (w naszym przypadku do tabeli bazy danych), a następnie je przetwarzamy.

W przypadku problemów z blokowaniem plików uruchamiam proces, który czeka na odblokowanie pliku, czekając jedną sekundę, potem dwie, potem cztery i tak dalej. Nigdy nie sondujemy. To trwało bezbłędnie przez około dwa lata.


źródło
12
Przepełnienie bufora? Och, masz na myśli przepełnienie stosu.
TheFlash,
1
Od .NET 3.5: „Bufor można ustawić na 4 KB lub większy, ale nie może on przekraczać 64 KB”
brad,
9
Jak używasz 16 MB, jeśli maksymalny bufor wewnętrzny dla FileSystemWatcher to 64 KB?
BK,
1
@ Jarvis, bufor jest tymczasową lokalizacją pamięci skonfigurowaną do przechowywania informacji, gdy są one przesyłane do czasu ich przetworzenia, zwykle oznacza to FIFO lub kolejkę, ponieważ chcesz obsługiwać żądania w kolejności, w jakiej przychodzą, jednak w niektórych procesach, takich jak rekursja w programach używana jest struktura FILO lub stosu, w tym przypadku zdecydowanie odnosimy się do bufora kolejki zdarzeń, a nie do programów wywołujących bufor stosu
MikeT
1
petermeinl.wordpress.com/2015/05/18/tamed-filesystemwatcher Ten post udostępnia solidne opakowania wokół standardowego programu FileSystemWatcher (FSW) naprawiającego problemy często napotykane podczas używania go do monitorowania systemu plików w rzeczywistych aplikacjach.
Kiquenet
35

FileSystemWatcherMoże również brakuje zmiany podczas porach, jeżeli liczba oczekujących zmian przepełnienia bufora celu. Nie jest to ograniczenie samej klasy .NET, ale podstawowej infrastruktury Win32. Z naszego doświadczenia wynika, że ​​najlepszym sposobem na zminimalizowanie tego problemu jest jak najszybsze usunięcie powiadomień z kolejki i zajęcie się nimi w innym wątku.

Jak wspomniano powyżej w @ChillTemp, obserwator może nie działać na udziałach innych niż Windows. Na przykład nie będzie w ogóle działać na zamontowanych dyskach Novell.

Zgadzam się, że dobrym kompromisem jest okazjonalne przeprowadzanie ankiet w celu wykrycia wszelkich pominiętych zmian.

Brent Rockwood
źródło
4
Obserwator systemu plików może zacząć zgłaszać wiele zdarzeń w krótkich odstępach czasu. Jeśli nie możesz wykonać procedury obsługi zdarzeń przynajmniej tak szybko, jak są one uruchamiane, w końcu program obsługi zacznie upuszczać zdarzenia na podłogę i przegapisz rzeczy.
Brent Rockwood
17

Należy również zauważyć, że obserwator systemu plików nie jest niezawodny w przypadku udziałów plików. Szczególnie jeśli udział plików jest hostowany na serwerze innym niż Windows. FSW nie powinno być używane do niczego krytycznego. Lub powinien być używany z okazjonalną ankietą, aby sprawdzić, czy nic nie pominęło.

chilltemp
źródło
3
Czy firma Microsoft przyznała, że ​​nie jest niezawodna w przypadku udziałów plików innych niż Windows? Z pewnością doświadczamy tego z pierwszej ręki od czasu przejścia z udziału Windows na udział SMB oparty na Linuksie.
Sean
1
Nie, że jestem świadomy. Jestem pewien, że byłaby to po prostu gra o winy między różnymi dostawcami.
chilltemp
1
Wystąpiły problemy z obserwatorem systemu plików na mapowanych dyskach. Jeśli mapa rozłączy się, a następnie ponownie połączy, obserwator plików nie zgłasza już zmian. Łatwo rozwiązany, ale nadal stanowi ostrzeżenie dla obserwatora systemu plików IMHO.
Richard Dorman
11

Osobiście korzystałem z FileSystemWatchersystemu produkcyjnego i działa dobrze. W ciągu ostatnich 6 miesięcy nie miał ani jednej czkawki działającej 24x7. Monitoruje pojedynczy folder lokalny (który jest udostępniany). Mamy stosunkowo niewielką liczbę operacji na plikach, które musi obsłużyć (10 zdarzeń uruchamianych dziennie). To nie jest coś, o co kiedykolwiek musiałam się martwić. Użyłbym go ponownie, gdybym musiał ponownie podjąć decyzję.

Jim
źródło
7

Obecnie używam FileSystemWatcher pliku XML, który jest aktualizowany średnio co 100 milisekund.

Zauważyłem, że dopóki FileSystemWatcherjest poprawnie skonfigurowany, nigdy nie powinieneś mieć problemów z lokalnymi plikami.

Nie mam doświadczenia w zdalnym oglądaniu plików i udostępnianiu innym niż Windows.

Uznałbym, że odpytywanie pliku jest zbędne i nie jest warte narzutów, chyba że z natury nie ufasz FileSystemWatcherlub bezpośrednio doświadczyłeś ograniczeń, które wszyscy tu wymienili (udziały spoza systemu Windows i zdalne obserwowanie plików).

Utrzymywanie wizji
źródło
5

Poszedłbym z ankietą.

Problemy z siecią powodują, że aplikacja FileSystemWatcherjest zawodna (nawet podczas przeciążania zdarzenia błędu).

niebieskawy
źródło
5

Mam problem z używaniem FileSystemWatcherna udziałach sieciowych. Jeśli pracujesz w czystym środowisku Windows, może to nie być problem, ale oglądałem udział NFS, a ponieważ NFS jest bezstanowy, nigdy nie było powiadomienia, gdy plik, który obserwowałem, zmienił się.

Jon Norton
źródło
Napotkałem ten sam problem, ale był to dla mnie nieoczekiwany, ponieważ FileSystemWatcher był na tym samym serwerze Windows, który współdzieli folder przy użyciu NFS. fakt współdzielenia folderu z NFS powoduje, że obserwator systemu plików nie widzi plików utworzonych zdalnie przy użyciu udziału (tj. z Linuksa, który mapuje udział), podczas gdy jeśli napiszę plik w tym samym folderze, który jest monitorowany, uruchamiany jest system plików. wygląda na to, że serwer NFS zapisuje pliki przy użyciu niższej warstwy i warstwy API, która wyzwala, gdy obserwator systemu plików nie jest zaangażowany, czy ktoś ma więcej informacji?
Mosè Bottacini
3

Miałem duże problemy z FSW na dyskach sieciowych: usunięcie pliku zawsze powodowało zdarzenie błędu, nigdy zdarzenie usunięte. Nie znalazłem rozwiązania, więc teraz unikam FSW i używam odpytywania.

Z drugiej strony zdarzenia tworzenia działały dobrze, więc jeśli potrzebujesz tylko patrzeć na tworzenie plików, możesz przejść do FSW.

Ponadto nie miałem żadnych problemów z folderami lokalnymi, bez względu na to, czy były udostępniane, czy nie.

Treb
źródło
3

Wracając jak najszybciej z metody eventowej, korzystając z innego wątku, rozwiązałem problem:

private void Watcher_Created(object sender, FileSystemEventArgs e)
{
    Task.Run(() => MySubmit(e.FullPath));
}
spludlow
źródło
2

Moim zdaniem używanie zarówno FSW, jak i pollingu jest stratą czasu i zasobów i jestem zaskoczony, że sugerują to doświadczeni programiści. Jeśli potrzebujesz użyć odpytywania, aby sprawdzić, czy nie ma żadnych błędów FSW, możesz oczywiście całkowicie odrzucić FSW i używać tylko odpytywania.

Obecnie próbuję zdecydować, czy do projektu, który rozwijam, użyję FSW czy ankietowania. Czytając odpowiedzi, jest oczywiste, że zdarzają się przypadki, w których FSW doskonale zaspokaja potrzeby, innym razem potrzebne jest sondowanie. Niestety, żadna odpowiedź nie dotyczyła różnicy w wydajności (jeśli taka istnieje), a jedynie kwestie „niezawodności”. Czy jest ktoś, kto może odpowiedzieć na tę część pytania?

EDYCJA: argument nmclean dotyczący zasadności używania zarówno FSW, jak i odpytywania (możesz przeczytać dyskusję w komentarzach, jeśli jesteś zainteresowany) wydaje się być bardzo racjonalnym wyjaśnieniem, dlaczego mogą wystąpić sytuacje, w których użycie zarówno FSW, jak i odpytywania jest wydajny. Dziękuję za rzucenie światła na to dla mnie (i każdego, kto ma to samo zdanie), nmclean .

ThunderGr
źródło
1
A jeśli chcesz jak najszybciej reagować na zmiany plików? Na przykład, jeśli odpytujesz raz na minutę, możesz mieć nawet 1 minutę opóźnienia między zmianą pliku a przyjęciem zmiany przez aplikację. Przypuszczalnie zdarzenie FSW zostałoby wywołane dużo wcześniej. Używając obu, obsługujesz zdarzenia z jak najmniejszym opóźnieniem, ale także odbierasz pominięte zdarzenia, jeśli takie istnieją.
rom99,
@ rom99 Dokładnie o co chodzi. Jeśli FSW jest zawodny w przypadkach, gdy potrzebujesz szybkiej odpowiedzi, nie ma sensu go używać, ponieważ będziesz mieć przypadki, w których nie będzie szybkiej odpowiedzi, a zatem Twoja aplikacja będzie zawodna. Sondowanie w krótszych odstępach czasu w wątku byłoby tym, co musisz zrobić. Robiąc jedno i drugie , oznacza to, że masz tolerancję w zakresie czasów odpowiedzi, które obejmuje ankieta, więc dlaczego nie użyć tylko odpytywania?
ThunderGr,
5
@ThunderGr "w ten sposób Twoja aplikacja będzie zawodna." - W wielu przypadkach szybkość nie jest warunkiem niezawodności. Praca musi zostać wykonana, ale może chwilę poczekać. Jeśli połączymy powolne, niezawodne odpytywanie z szybkim, zawodnym FSW, otrzymamy aplikację, która jest zawsze niezawodna, a czasem szybka, która jest lepsza niż niezawodna i nigdy nie jest szybka. Możemy usunąć FSW i osiągnąć ten sam maksymalny czas odpowiedzi, wykonując ciągłe odpytywanie, ale odbywa się to kosztem responsywności reszty aplikacji, więc należy to robić tylko wtedy, gdy natychmiastowa odpowiedź jest absolutnie wymagana.
nmclean
2
Teraz , dlaczego jest powyżej złym argumentem? Ponieważ chociaż nadal potrzebujemy dostępu do dysku, potrzebujemy go mniej . Podobnie możesz mniej sondować. To, że nadal sprawdzamy wszystkie pliki, nie oznacza, że ​​obciążenie jest takie samo. Twoje stwierdzenie, „sondowanie jest drogie z uwagi na czas procesora z FSW czy nie”, jest fałszywe . Odciążając FSW problem „natychmiastowości”, możemy zmienić odpytywanie na bezczynne zadanie o niskim priorytecie, tak że zajętość aplikacji w danym momencie jest drastycznie zmniejszona, a jednocześnie zapewnia „przyjemność” natychmiastowości. Po prostu nie można osiągnąć tej samej równowagi, stosując same ankiety.
nmclean
9
@nmclean Dziękujemy za poświęcenie czasu i energii na wyjaśnienie tego w sposób, w jaki to zrobiłeś. Kiedy tak to ujmujesz, z pewnością ma to znacznie więcej sensu. Tak jak są chwile, kiedy pamięć podręczna nie jest odpowiednia dla twojego konkretnego problemu, tak FSW (gdy okaże się zawodne) może nie być odpowiedni. Okazuje się, że przez cały czas miałeś rację. Przepraszam, że zajęło mi to tyle czasu.
ThunderGr
1

Działające rozwiązanie do pracy z utworzeniem wydarzenia zamiast zmiany

Nawet do kopiowania, wycinania, wklejania, przenoszenia.

class Program
{        

        static void Main(string[] args)
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";
            FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
            FileSystemWatcher.Path = SourceFolderPath;
            FileSystemWatcher.IncludeSubdirectories = false;
            FileSystemWatcher.NotifyFilter = NotifyFilters.FileName;   // ON FILE NAME FILTER       
            FileSystemWatcher.Filter = "*.txt";         
             FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED  BY COPY, CUT PASTE, MOVE  
            FileSystemWatcher.EnableRaisingEvents = true;

            Console.Read();
        }     

        static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {           
                string SourceFolderPath = "D:\\SourcePath";
                string DestinationFolderPath = "D:\\DestinationPath";

                try
                {
                    // DO SOMETING LIKE MOVE, COPY, ETC
                    File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
                }
                catch
                {
                }          
        }
}

Rozwiązanie dla tego obserwatora plików podczas zdarzenia zmiany atrybutu pliku przy użyciu pamięci statycznej

class Program
{
    static string IsSameFile = string.Empty;  // USE STATIC FOR TRACKING

    static void Main(string[] args)
    {
         string SourceFolderPath = "D:\\SourcePath";
        string DestinationFolderPath = "D:\\DestinationPath";
        FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
        FileSystemWatcher.Path = SourceFolderPath;
        FileSystemWatcher.IncludeSubdirectories = false;
        FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;          
        FileSystemWatcher.Filter = "*.txt";         
        FileSystemWatcher.Changed += FileSystemWatcher_Changed;
        FileSystemWatcher.EnableRaisingEvents = true;

        Console.Read();
    }     

    static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (e.Name == IsSameFile)  //SKIPS ON MULTIPLE TRIGGERS
        {
            return;
        }
        else
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";

            try
            {
                // DO SOMETING LIKE MOVE, COPY, ETC
                File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
            }
            catch
            {
            }
        }
        IsSameFile = e.Name;
    }
}

Jest to rozwiązanie obejścia tego problemu związanego z wieloma zdarzeniami wyzwalającymi.

Mark Macneil Bikeio
źródło
0

Powiedziałbym, że używaj odpytywania, szczególnie w scenariuszu TDD, ponieważ znacznie łatwiej jest wyszydzać / odgiąć obecność plików lub w inny sposób, gdy zdarzenie odpytywania jest wyzwalane, niż polegać na bardziej „niekontrolowanym” zdarzeniu fsw. + do tego, że pracował nad wieloma aplikacjami, które były nękane przez błędy FSW.

user2819502
źródło