13 Stimmen

FileSystemWatcher und Windows 7

Ich schreibe ein Tool, das einen Netzwerkordner überwacht und auf einem Windows Server 2008 läuft, das OnChanged-Ereignis für den FileSystemWatcher wird korrekt von Dateien ausgelöst, die von einem beliebigen Computer auf dem Netzlaufwerk platziert werden, der nicht Windows 7 verwendet. Aus irgendeinem Grund werden keine Ereignisse ausgelöst, wenn auf einem Windows 7-Computer mehr als 19 Dateien gleichzeitig kopiert werden, obwohl es funktioniert, wenn Dateien einzeln kopiert werden. Gibt es eine Lösung dafür oder ist das einfach das Verhalten des Windows 7-Kernels bei FSW-Ereignissen?

Nur zur Klarstellung, es funktioniert für Tausende von Dateien, wenn sie von einem XP-Computer kopiert werden. (Die Software befindet sich immer noch auf dem 2008-Server).

22voto

Dirk Vollmar Punkte 166522

Von MSDN:

Das Windows-Betriebssystem benachrichtigt Ihr Komponente über Dateiänderungen in einem vom FileSystemWatcher erstellten Puffer. Wenn es viele Änderungen in kurzer Zeit gibt, kann der Puffer überlaufen. Dies führt dazu, dass die Komponente den Überblick über Änderungen im Verzeichnis verliert und nur eine allgemeine Benachrichtigung bereitstellt. Das Erhöhen der Größe des Puffers mit der InternalBufferSize-Eigenschaft ist teuer, da er aus nicht auszulagerndem Speicher stammt. Halten Sie den Puffer also klein, aber groß genug, um keine Dateiänderungsereignisse zu verpassen. Um ein Pufferüberlauf zu vermeiden, verwenden Sie die Eigenschaften NotifyFilter und IncludeSubdirectories, um unerwünschte Änderungsbenachrichtigungen herauszufiltern.

Wenn das Erhöhen der Puffergröße nicht ausreicht und Sie nicht steuern können, wie viele Dateien gleichzeitig Ereignisse auslösen, müssten Sie zusätzliches Polling hinzufügen.

Sehen Sie auch diese verwandte Frage:

FileSystemWatcher funktioniert nicht richtig, wenn viele Dateien gleichzeitig zum Verzeichnis hinzugefügt werden…

Aktualisierung:

Es könnte verlockend sein, einfach die Puffergröße zu erhöhen, aber dies sollte mit Vorsicht geschehen. Tatsächlich gibt es eine 64-KB-Beschränkung für den Netzwerkzugriff. Die Klasse FileSystemWatcher verwendet die Windows-API-Funktion ReadDirectoryChangesW, die diese Grenze hat:

ReadDirectoryChangesW schlägt mit ERROR_INVALID_PARAMETER fehl, wenn die Pufferlänge größer als 64 KB ist und die Anwendung ein Verzeichnis über das Netzwerk überwacht. Dies liegt an einer Paketgrößenbeschränkung der zugrunde liegenden Dateifreigabeprotokolle.

Wenn Sie ein tieferes Verständnis der Kosten für die Änderung der Puffergröße wünschen, sollten Sie den Beitrag von Walter Wang von Microsoft hier lesen:

FileSystemWatcher über das Netzwerk (voller Beitrag unten zitiert)

Es tut mir leid, dass die Dokumentation von FileSystemWatcher.InternalBufferSize nicht sehr deutlich über die Puffergröße beim Überwachen von Netzwerkpfaden informiert. Es wird empfohlen, nicht mehr als 64K zu überschreiten, wenn ein Netzwerkpfad überwacht wird.

FileSystemWatcher ist im Grunde eine .Net-Umwicklung für die Win32 ReadDirectoryChangesW-API. Um ReadDirectoryChangesW zu verwenden, erstellen und geben Sie einen Puffer an, den das Betriebssystem mit den Änderungen füllen wird. Was jedoch nicht in der ReadDirectoryChangesW-Dokumentation erwähnt wird (aber in der FileSystemWatcher-Dokumentation angedeutet wird), ist dass das Dateisystem einen internen Kernelpuffer erstellt, um die Änderungsinformationen temporär zu speichern, bis es die Chance hat, den Benutzerpuffer zu aktualisieren. Die Größe des erstellten Kernelpuffers entspricht der in ReadDirectoryChangesW angegebenen Größe und wird im nicht ausgelagerten Pool-Speicher erstellt. Jedes Mal, wenn ein FileSystemWatcher / ReadDirectoryChangesW erstellt / aufgerufen wird, wird auch ein neuer Kernelpuffer erstellt.

Die Kernel-Speicher-Pools (ausgelagert und nicht ausgelagert) werden im Systemadressraum für Gerätetreiber und andere Kernelkomponenten reserviert. Sie wachsen und schrumpfen dynamisch, wie es erforderlich ist. Die aktuellen Größen der Pools können einfach im Leistungs-Tab des Task-Managers eingesehen werden. Die Pools werden dynamisch wachsen, bis sie einen maximalen Wert erreichen, der beim Booten berechnet wird und von den verfügbaren Systemressourcen (hauptsächlich RAM) abhängt. Sie möchten diesen maximalen Wert nicht erreichen, da sonst verschiedene Systemdienste und Treiber ausfallen werden. Der berechnete maximale Wert ist jedoch nicht leicht verfügbar. Um die maximalen Poolgrößen zu bestimmen, müssen Sie einen Kernel-Debugger verwenden. Wenn Sie an weiteren Informationen über die Speicherpools des Systems interessiert sind, empfehle ich Ihnen, das Kapitel 7 des MSPress-Buchs Inside Windows 2000 von Solomon und Russinovich zu studieren.

In diesem Zusammenhang gibt es keine Empfehlung zur Verwendung von Puffergrößen. Die aktuellen und maximalen Größen der Systempools variieren von Klient zu Klient. Sie sollten jedoch wahrscheinlich nicht über 64k für jeden FileSystemWatcher / ReadDirectoryChangesW-Puffer gehen. Dies ergibt sich aus der Tatsache, dass es eine 64k-Beschränkung für den Netzwerkzugriff gibt, wie in ReadDirectoryChangesW dokumentiert. Aber am Ende müssen Sie die Anwendung auf einer Vielzahl von erwarteten Zielsystemen testen, damit Sie Ihren Puffer optimieren können.

Mit dieser Überlegung gibt es Overhead-Kosten im Zusammenhang mit .Net-Anwendungen und ich stelle mir vor, dass ein Win32-ReadDirectoryChangesW-Programm mit derselben Puffergröße möglicherweise bessere Leistung erzielen könnte. Bei sehr schnellen und zahlreichen Dateiänderungen sind Pufferüberläufe jedoch unvermeidlich und der Entwickler muss den Fall behandeln, wenn ein Überlauf auftritt, wie z.B. das manuelle Aufzählen des Verzeichnisses, um die Änderungen zu erkennen.

Zusammenfassend sind FileSystemWatcher und ReadDirectoryChangesW ein leichtgewichtiges Dateiänderungserkennungssystem, das seine Grenzen haben wird. Change Journals ist ein anderes System, das wir als mittelschwere Lösung betrachten würden, aber auch Einschränkungen haben:

http://msdn.microsoft.com/en-us/library/aa363798%28VS.85%29.aspx

Schwere Lösungen wären die Entwicklung eines dedizierten Dateisystemfiltertreibers, der im Dateisystemstack sitzt und Dateisystemänderungen überwacht. Natürlich wäre dies der komplexeste Ansatz. Die meisten Virenscanner, Backup-Software und Dateisystemüberwachungsdienstprogramme wie filemon (www.sysinternals.com) implementieren einen Filtertreiber.

Ich hoffe, die obige Erläuterung hilft Ihnen, die Ursache des Problems zu verstehen, das Sie erleben. Bitte antworten Sie, um uns mitzuteilen, ob Sie weitere Informationen benötigen. Danke.

0 Stimmen

Nur eine kleine Ergänzung: Die Standardpuffergröße beträgt 8192.

4voto

Justin Punkte 3832

Nach vielen, vielen Versuchen mit dem FileSystemWatcher habe ich aufgegeben. Es löst Ereignisse nicht korrekt aus, zur falschen Zeit, vom falschen Typ. Ehrlich gesagt glaube ich, dass es eine der schlechtesten Klassen im .NET-Framework ist. Ich habe immer meine eigene Klasse geschrieben, die einen System.Timer verwendet und nach x Millisekunden überprüft, ob Verzeichnisse, Dateien manuell vorhanden sind. Ja, es bedeutet mehr Arbeit und ja, es kann etwas nervig sein, aber sobald Sie es geschrieben haben, können Sie es überall verwenden. Ich wünschte, der FileSystemWatcher würde so funktionieren, wie es beworben wird, aber das war in meinem Fall nie der Fall.

0 Stimmen

Ich stimme zu, dass FileSystemWatcher offensichtlich nicht in allen Situationen geeignet ist. Allerdings bietet es eine Funktion, die mit einer einfachen Verzeichnisauflistung nur schwer zu erreichen ist: das Erkennen von Dateiumbenennungen. Es ist möglich (durch Dateieigenschaftsvergleiche, Heuristiken, MD5-Prüfsummen usw.), aber es ist mühsam.

0 Stimmen

@stakx, das ist sehr wahr, ich habe nie versucht, nach Dateinamenänderungen zu suchen. Ich wurde einfach so oft von dieser Klasse verbrannt, dass ich sie nie benutze.

2voto

Die meiste Zeit, wenn ein FileSystemWatcher-Ereignis ausgelöst wird, ignoriere ich die Dateien, die vom Objekt übergeben werden, da diese Liste unvollständig sein kann.

Ich durchsuche einfach das Verzeichnis, das vom FileSystemWatcher-Objekt überwacht wird, und führe einen manuellen Scan durch, um die Dateien zu finden, die möglicherweise nicht im FileSystemWatcher-Puffer vorhanden sind. Es ist nicht wirklich elegant, aber es stellt sicher, dass Sie keine Datei verpassen.

0 Stimmen

Das scheint ein völlig separates Thema zu sein, das nichts mit der Inkonsistenz zu tun hat, über die der OP spricht.

0 Stimmen

@Chad: Wie scheint dies völlig unabhängig? Ich würde sagen, es klingt genau wie eine Methode, um das Problem des OPs zu umgehen.

0 Stimmen

Weil der OP sagt, dass das Ereignis überhaupt nicht ausgelöst wird. Laurens schlägt vor, dass wenn das Ereignis ausgelöst wird sie manuell das Verzeichnis überprüfen, aber wenn das Ereignis erst gar nicht ausgelöst wird, kann der OP dies nicht tun. Daher bezieht sich Laurens' Kommentar nicht auf das gleiche Problem, das der OP sieht. Zumindest so lese ich die Frage des OP in Bezug auf Laurens' Kommentar.

0voto

Jesus Ramos Punkte 22582

Dies ist wirklich eine sehr unzuverlässige Klasse, wenn Dateien über einem bestimmten Schwellenwert liegen, habe ich Ereignisse erlebt, die etwa 7 Mal bei der ersten Kopie ausgelöst werden und dann, wenn der Dateiübertragungsdialog abgeschlossen ist, erhalte ich weitere 7 Ereignisse. Dieses Problem tritt bei allen Betriebssystemen auf, die den FSW unterstützen. Obwohl Windows 7 (habe noch nicht Vista ausprobiert) immer noch nur Dateien einzeln oder 19 gleichzeitig akzeptiert, wenn ich Dateien von einem XP-Maschine in das Netzlaufwerk ziehe, kann ich Tausende von Dateien gleichzeitig lesen, ohne Probleme zu haben. Dies könnte einfach nur eine Änderung von ReadDirectoryChangesW von XP zu 7 sein. Nach 19 Dateien konnte ich KEIN Ereignis auslösen lassen, also wird das vorerst wohl ein "Feature" meines Tools werden. Wenn jemand weitere Informationen hat, gerne beitragen.

-1voto

Eric Kung Punkte 33

Wenn Sie MacOSX + Parallels Desktop + Windows verwenden, Ihr Code funktioniert nicht, Weil Ihr FileSystemWatcher.Path-Eigenschaft auf den Mac-Pfad zielt, es handelt sich um einen UNC-Pfad, der nicht unterstützt wird!

Bildbeschreibung hier eingeben

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X