Laden...

FilesystemWatcher nur ein gefeuertes Event verwerten

Erstellt von Rioma vor 7 Jahren Letzter Beitrag vor 7 Jahren 4.030 Views
R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 7 Jahren
FilesystemWatcher nur ein gefeuertes Event verwerten

Hallo zusammen,

ich habe ein kleines Problem mit dem Verhalten des FilesystemWatchers. Bekanntlich werden für eine Datei die Events häufig mehrfach gefeuert (Es geht nur um das OnCreated).

Ich würde das Event aber gerne nur einmal verarbeiten, bis die Datei wieder von mir "freigegeben" wurde.
Ich habe im Handler ein Hashset erstellt und füge den Pfad hinzu. Sollte das fehlschlagen, würde die eigentliche Aktion nicht ausgelöst werden.


 private HashSet<string> files = new HashSet<string>();

        private void FileCreated(object sender, FilePathEventArgs e)
        {
            try
            {
                if (files.Add(e.FilePath))
                   //aktion();
            }
            catch (Exception ex)
            {
//Test
            }

        }

Die Add Funktion ist natürlich nicht atomar und die Events werden so schnell gefeuert, das die Aktion dennoch 2 Mal ausgeführt wird.

Hat jemand eine andere Idee?

Danke

J
251 Beiträge seit 2012
vor 7 Jahren

Event beim 1. Auslösen deabonnieren und beim "Freigeben" wieder abonnieren ist keine Option?

2.207 Beiträge seit 2011
vor 7 Jahren

Hallo Rioma,

du könntest mit ner boolschen Variable abfragen, ob du das Event überhaupt ausführen sollst. Im finally setzt dus dann weider auf true. Das ist zwar nicht schön, aber vielleicht hilft es ja.

Grad gefunden:

  1. Events being raised twice - An event will be raised twice if an event handler (AddHander FSW.Created, AddressOf FSW_Created) is explicitly specified. This is because, by default, the public events automatically call the respective protected methods (OnChanged, OnCreated, OnDeleted, OnRenamed). To correct this problem, simply remove the explicit event handler (AddHandler ...).

Gruss

Coffeebean

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 7 Jahren

Deabonnieren ist keine Option, da so potentielle andere Dateien übersehen werden.

Die Abfrage des booleschen Wertes müsste aber auf Dateiebene stattfinden. Da andere Dateien natürlich noch verarbeitet werden sollen. Ich denke ich werde hier ebenfalls das Problem haben, dass dies zu langsam ist.
Das Event habe ich nicht explizit abonniert.


 _fileSystemWatcher.Created += FileSystemWatcherOnCreated;

Ich denke mein Problem ist hier erklärt:

FileSystemWatcher Changed event is raised twice

2.207 Beiträge seit 2011
vor 7 Jahren

Ich denke mein Problem ist hier erklärt:

Heisst das, du hast das Problem mit dem SO-Thread gelöst? Wenn ja: Wie? Oder heisst das nur, dass dies dein Problem noch besser beschreibt?

Gruss

Coffeebean

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 7 Jahren

Gelöst leider nicht. Ich wollte damit nur sagen, dass mein Problem nicht von den expliziten Eventhandlern kommt.

Absolut letzte Option wäre RX:


var watcher = new FileSystemWatcher("./");

Observable.FromEventPattern<FileSystemEventArgs>(watcher, "Changed")
            .Throttle(new TimeSpan(500000))
            .Subscribe(HandleChangeEvent);

watcher.EnableRaisingEvents = true;

Aber ich füge eine lib natürlich ungern für eine einzige Stelle hinzu.

Edit: Der Code ist aus dem Link

16.806 Beiträge seit 2008
vor 7 Jahren

Dein Wunsch ist so vom FSW nicht abgedeckt. Dass bei einem Create zwei Events gefeuert werden, ist nichts neues und by design
Ergo musst Du das selbst umsetzen.

M
19 Beiträge seit 2012
vor 7 Jahren

Hast Du schon mal das Deleted Event angeschaut?
Wenn man zum Beispiel mit Notepad++ eine Datei speichert, passiert folgendes:

Created -> Deleted -> Created

Könnte man wie folgt abfangen:


        private static void watcher_Created(object sender, System.IO.FileSystemEventArgs e)
        {
            var time = File.GetCreationTimeUtc(e.FullPath);
            long offset = 504911232000000000;
            if (offset == time.Ticks) return;
            Console.WriteLine("Created " + e.Name);
        }

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 7 Jahren

Das ich das nicht verhindern kann, ist mir bewusst.

Deswegen habe ich versucht, das Problem mit dem Hashset zu umgehen. Allerdings ohne erfolg. Ich bekomme 2 Mal ein true zurück und am Ende ist der Pfad nur einmal drin.

Füge ich die Datei nun ein weiteres Mal hinzu, gibt es keine Probleme. Die events sind einfach zu kurz hintereinander.

16.806 Beiträge seit 2008
vor 7 Jahren

Race Condition, da Du in verschiedenen Thread bist und vergessen hast zu synchronisieren?

R
Rioma Themenstarter:in
228 Beiträge seit 2013
vor 7 Jahren

Ich hatte anfangs nicht daran gedacht, allerdings dann hinzugefügt.

Funktionieren tut es aber nur, wenn das Hashset static ist. Woran liegt das?
Ohne static befindet sich die variable auf Instanz-Ebene und davon sollte es nur eine geben.

Erzeugt wird diese von Topshelf:


   HostFactory.Run(config =>
            {
                // Pass it to Topshelf
                config.UseSimpleInjector(_container);
                config.UseNLog();

                config.Service<Service>(s => //Service ist die Instanz
                {
                    s.ConstructUsingSimpleInjector();
                    s.WhenStarted((service, control) => service.Start(control));
                    s.WhenStopped((service, control) => service.Stop(control));
                });

                config.RunAsLocalSystem();                            

            });