FileSystemWatcher - Kein Event wenn Ordner umbenannt wird

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    FileSystemWatcher - Kein Event wenn Ordner umbenannt wird

    Hallo an alle :)

    Ich versuche mich gerade an einem Testprogramm mit dem FileSystemWatcher.

    Funktioniert soweit ganz gut, bis auf dass, wenn ich einen (mit Dateien befüllten) Ordner umbenenne, kein Event gefeuert wird... Ebenso wenn ich einen Ordner verschiebe bzw. ausschneide und woanders einfüge. Wenn ich den Ordner bloss kopiere funktioniert es komischerweise. Mir ist klar und das ist auch so gewollt, dass nicht der Ordner in der Konsole ausgegeben wird, sondern nur die darin befindlichen Dateien.

    Hier mal mein Code:

    VB.NET-Quellcode

    1. ​Option Strict On
    2. Module Module1
    3. Sub Main()
    4. Using DateiWatcher = New System.IO.FileSystemWatcher()
    5. DateiWatcher.Filter = "*.txt"
    6. DateiWatcher.Path = "F:\Ablage\dateiwatcher"
    7. DateiWatcher.IncludeSubdirectories = True
    8. DateiWatcher.EnableRaisingEvents = True
    9. DateiWatcher.NotifyFilter = System.IO.NotifyFilters.LastWrite Or System.IO.NotifyFilters.FileName Or System.IO.NotifyFilters.DirectoryName
    10. AddHandler DateiWatcher.Changed, AddressOf WennGeaendert
    11. AddHandler DateiWatcher.Created, AddressOf WennErstellt
    12. AddHandler DateiWatcher.Deleted, AddressOf WennGeloescht
    13. AddHandler DateiWatcher.Changed, AddressOf WennGeaendert
    14. AddHandler DateiWatcher.Renamed, AddressOf WennUmbenannt
    15. AddHandler DateiWatcher.Error, AddressOf WennFehler
    16. Console.ReadLine()
    17. End Using
    18. End Sub
    19. Private Sub WennGeaendert(sender As Object, e As System.IO.FileSystemEventArgs)
    20. Console.WriteLine("Diese Datei wurde geändert: " & e.FullPath)
    21. End Sub
    22. Private Sub WennErstellt(sender As Object, e As System.IO.FileSystemEventArgs)
    23. Console.WriteLine("Diese Datei wurde neu erstellt: " & e.FullPath)
    24. End Sub
    25. Private Sub WennGeloescht(sender As Object, e As System.IO.FileSystemEventArgs)
    26. Console.WriteLine("Diese Datei wurde gelöscht: " & e.FullPath)
    27. End Sub
    28. Private Sub WennUmbenannt(sender As Object, e As System.IO.RenamedEventArgs)
    29. Console.WriteLine("Diese Datei wurde umbenannt von: " & e.OldFullPath & Environment.NewLine & "zu: " & e.FullPath)
    30. End Sub
    31. Private Sub WennFehler(sender As Object, e As System.IO.ErrorEventArgs)
    32. Console.WriteLine("Ein Fehler ist aufgetreten: " & e.GetException.ToString)
    33. End Sub
    34. End Module
    it's not a bug, it's a feature:

    Microsoft schrieb:

    This has always been the behavior and is an artifact of the underlying Win32 API- docs.microsoft.com/en-us/windo…ase-readdirectorychangesw. You need to watch the parent directory. You can mitigate cost by not watching recursively and adding as many filters as possible.

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    kafffee schrieb:

    VB.NET-Quellcode

    1. AddHandler DateiWatcher.Changed, AddressOf WennGeaendert
    kommt zwei Mal vor. Wenn Du in diese Prozedur einen Zähler rein baust, wirst Du feststellen, dass sie tatsächlich doppelt so oft aufgerufen wird. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Nein, wenn Du Umbenennungen von F:\Ablage\dateiwatcher erfassen willst, sollst Du eben dessen ParentDirectory überwachen, also F:\Ablage
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed

    Achso meinst du. Ne das ist schon klar. Hab ich mich undeutlich ausgedrückt:

    Ich will ja nicht F:\Ablage\dateiwatcher selbst umbenennen, sondern die darin befindlichen Ordner...

    Edit:
    MS Docs sagt doch eindeutig:
    .RenamedEvent "Occurs when a file or directory in the specified Path is renamed."

    Auf stackoverflow.com/questions/51…r-to-detect-folder-rename
    sagt zwar einer man soll das .FolderRenamed-Event abonnieren, IntelliSense bietet mir etwas derartiges aber nicht an... :(

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „kafffee“ ()

    kafffee schrieb:

    Hier mal mein Code:
    Wenn du Using verwendest, dann passiert bei End Using ein Disposen deines Watchers und es passiert danach gar nichts...

    kafffee schrieb:

    DateiWatcher.Filter = "*.txt"
    Mache es ohne Using und kommentiere obige Zeile aus, dann werden auch Umbenennungen deiner SubOrdner gemeldet...

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „VB1963“ ()

    @VB1963

    OK schon besser. Idealerweise möchte ich jetzt für jede Datei im Ordner OrdnerX, ein Event haben, wenn dieser geändert, gelöscht oder umbenannt wurde. Also nicht, dass z.B. OrdnerX umbenannt wurde, sondern ein eigenes Event für jede Datei, die da drin ist... Das würde die Sache sehr, sehr vereinfachen...

    kafffee schrieb:

    Idealerweise möchte ich jetzt für jede Datei im Ordner OrdnerX, ein Event haben, wenn dieser geändert, gelöscht oder umbenannt wurde
    Sind den die Informationen der Files und Ordner denn nicht in den einzelnen EventArgs zu entnehmen? Oder wie meinst du das jetzt...
    @kafffee Sieh Dir doch mal die Events und die Notifies des FileSystemWatchers an, da findest Du alles: docs.microsoft.com/de-de/dotne…cher.changed?view=net-6.0
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany
    Ja das hab ich bereits durchgelesen, da hab ich das Testprogramm drauf aufgebaut.

    VB1963 schrieb:

    Sind den die Informationen der Files und Ordner denn nicht in den einzelnen EventArgs zu entnehmen? Oder wie meinst du das jetzt...

    Doch die auszulesen ist kein Problem.

    Das Problem ist Folgendes:
    Ich habe eine List(of MeineKlasse). In einer der Properties von MeineKlasse ist jeweils der volle Pfad (inkl. Dateiname) einer MP3-Datei als String hinterlegt.

    Nun soll die Liste geupdatet werden, wenn sich im angegebenen Ordner was an den Dateien/Ordner geändert wird.

    So, wenn jetzt aber ein Ordner umbenannt wird, dann bekomm ich ja nur durch das Event mit, dass der Ordner umbenannt wird. Mir wäre es aber lieber, wenn ich für jede Datei in diesem Ordner eine gesonderte Meldung bekommen würde, das würde den Vorgang extrem vereinfachen. Ansonsten müsste ich mir da eine Routine schreiben, die das Ganze auseinander klamüstert....

    Ich verstehe nicht, warum ich dann kein .Changed-Ereignis für die einzelnen Dateien bekomme, denn ich habe ja in den Filtereinstellungen drin, dass wenn sich, wenn sich .DirectoryName ändert, ich dementsprechend ein Event ausgelöst bekomm... Oder übersehe ich da etwas?

    VB.NET-Quellcode

    1. DateiWatcher.NotifyFilter = System.IO.NotifyFilters.LastWrite Or System.IO.NotifyFilters.FileName Or System.IO.NotifyFilters.DirectoryName


    PS: Das angehängte Testprogramm ist lauffähig und ohne externe Verweise. Nur in Zeile 8 muss man noch das Verzeichnis ändern...
    Dateien

    kafffee schrieb:

    Ich habe eine List(of MeineKlasse).
    Ich finde in deiner angehängten Testsolution diese Klasse nicht...

    kafffee schrieb:

    Ich verstehe nicht, warum ich dann kein .Changed-Ereignis für die einzelnen Dateien bekomme
    es wird schon genau alles gemeldet, wenn sich eine Datei im Überwachungsordner und in seinen Unterordnern geändert hat und wird auch genau ausgegeben - selbst das Umbenennen eines Unterordners etc. ...
    @VB1963

    Ah sry: Die Klasse ist in meinem Hauptprojekt, das Testprogramm ist wirklich nur ein Testprogramm.

    es wird schon genau alles gemeldet, wenn sich eine Datei im Überwachungsordner und in seinen Unterordnern geändert hat und wird auch genau ausgegeben - selbst das Umbenennen eines Unterordners etc. ...


    Ehrlich? Bei mir nicht. Wenn ich einen Unterordner umbenenne wird nur gemeldet, dass der Unterordner umbenannt wurde, nichts von den darin befindlichen Dateien...
    Nur wenn ich einen Unterordner kopiere und woanders hin wieder einfüge, dann funktioniert es...

    kafffee schrieb:

    Ehrlich? Bei mir nicht.
    Bei mir schon?

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.IO
    3. Module Module1
    4. Private WithEvents DateiWatcher As FileSystemWatcher = New FileSystemWatcher()
    5. Sub Main()
    6. DateiWatcher.Path = "F:\Ablage\dateiwatcher"
    7. DateiWatcher.IncludeSubdirectories = True
    8. DateiWatcher.EnableRaisingEvents = True
    9. DateiWatcher.NotifyFilter = NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName
    10. Console.ReadLine()
    11. End Sub
    12. Private Sub WatcherError(sender As Object, e As ErrorEventArgs) Handles DateiWatcher.Error
    13. Console.WriteLine("Ein Fehler ist aufgetreten: " & e.GetException.ToString)
    14. End Sub
    15. Private Sub WatcherAction(sender As Object, e As FileSystemEventArgs) Handles DateiWatcher.Changed, DateiWatcher.Created, DateiWatcher.Deleted, DateiWatcher.Renamed
    16. Dim fi = New FileInfo(e.FullPath)
    17. Dim isDirectory = fi.Attributes = FileAttributes.Directory
    18. Console.WriteLine($"Diese{If(isDirectory, "r Ordner", " Datei")} wurde { GetAction(e.ChangeType)}: " & e.FullPath)
    19. End Sub
    20. Private Function GetAction(action As WatcherChangeTypes) As String
    21. Select Case action
    22. Case = WatcherChangeTypes.Changed : Return "geändert"
    23. Case = WatcherChangeTypes.Created : Return "erstellt"
    24. Case = WatcherChangeTypes.Deleted : Return "gelöscht"
    25. Case = WatcherChangeTypes.Renamed : Return "umbenannt"
    26. Case Else : Return "???"
    27. End Select
    28. End Function
    29. End Module​
    Ich habe diesen Code von dir abgeändert...
    Aus ErrorEventArgs kannst du sämtliche Informationen herausholen, die du brauchst...
    @VB1963

    Ja gut wie ich das sehe ist das grösstenteils einfach eine andere Schreibweise wie das von mir, mit derselben Funktion. Und es hat den selben Effekt, nämlich dass er bei mir nur anzeigt, dass der Unterordner umbenannt wurde, nicht die einzelnen Dateien da drin.

    Wenn es bei dir geht, dann ist das echt komisch....

    Probier mal Folgendes (egal ob mit meinem oder deinem Code):

    Ausgangsordner:
    C:\DeineWahl

    Darin erstellst du einen Unterordnder, von mir aus:
    C:\DeineWahl\Neuer Ordner

    In diesem Unterordner legst du eine Datei an, von mir aus:
    C:\DeineWahl\Neuer Ordner\Neues Textdokument.txt

    So, also wenn das so funktioniert, wie ich mir das wünsche, dann sollte, wenn du C:\DeineWahl\Neuer Ordner umbenennst, nicht die Ausgabe Dieser Ordner wurde umbenannt: C:\DeineWahl\Neuer Ordner kommen. sondern so was:
    Diese Datei wurde umbenannt von: C:\DeineWahl\Neuer Ordner\Neues Textdokument.txt zu C:\DeineWahl\Neuer Ordner ABC\Neues Textdokument.txt

    Jetzt solltest du verstehen wie ich meine.

    @VB1963
    Hab mal kurz was geschrieben was den gewünschten Effekt hat:

    VB.NET-Quellcode

    1. Module Module1
    2. Public Event OrdnerUmbenannt(DateiNeu As String, DateiAlt As String)
    3. Sub Main()
    4. AddHandler OrdnerUmbenannt, AddressOf OrdnerWurdeUmbenannt
    5. [...]
    6. End Sub
    7. Private Sub WennUmbenannt(sender As Object, e As System.IO.RenamedEventArgs)
    8. Console.WriteLine("Diese Datei wurde umbenannt von: " & e.OldFullPath & Environment.NewLine & "zu: " & e.FullPath)
    9. Dim DateiInfoAlt As System.IO.FileInfo = New System.IO.FileInfo(e.OldFullPath)
    10. Dim DateiInfoNeu As System.IO.FileInfo = New System.IO.FileInfo(e.FullPath)
    11. If DateiInfoNeu.Attributes = IO.FileAttributes.Directory Then
    12. For Each DateiNeu In System.IO.Directory.GetFiles(e.FullPath)
    13. Dim DateiAlt = e.OldFullPath & "\" & System.IO.Path.GetFileName(DateiNeu)
    14. RaiseEvent OrdnerUmbenannt(DateiNeu, DateiAlt)
    15. Next
    16. End If
    17. End Sub
    18. Private Sub OrdnerWurdeUmbenannt(DateiNeu As String, DateiAlt As String)
    19. Console.WriteLine("Diese Datei wurde umbenannt von: " & DateiAlt & Environment.NewLine & "zu: " & DateiNeu)
    20. End Sub


    Aber würd mich trotzdem irgendwie interessieren, warum ich das nicht direkt haben kann... ?(

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    @kafffee Pack das ganze mal in eine Form, zieh Dir den FSW drauf und arbeite so mit den Events, wie das bei Forma vorgesehen ist.
    In einem Modul ist das ggf. etwas anders.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    kafffee schrieb:

    So, also wenn das so funktioniert, wie ich mir das wünsche, dann sollte, wenn du C:\DeineWahl\Neuer Ordner umbenennst, nicht die Ausgabe Dieser Ordner wurde umbenannt: C:\DeineWahl\Neuer Ordner kommen. sondern so was:
    Diese Datei wurde umbenannt von: C:\DeineWahl\Neuer Ordner\Neues Textdokument.txt zu C:\DeineWahl\Neuer Ordner ABC\Neues Textdokument.txt
    Verwechselst du da jetzt nicht Ordner mit File ? Das sind verschiedene Dinge...

    Wenn ich im Überwachungsordner einen neuen Ordner erstelle kommt folgende Meldung:
    Dieser Ordner wurde erstellt: E:\__G__\Neuer Ordner

    Wenn ich in den neuen Ornder eine Textdatei hineinspeichere kommt:
    Diese Datei wurde erstellt: E:\__G__\Neuer Ordner\TestFile.txt Diese Datei wurde gelöscht: E:\__G__\Neuer Ordner\TestFile.txt Dieser Ordner wurde geändert: E:\__G__\Neuer Ordner Diese Datei wurde erstellt: E:\__G__\Neuer Ordner\TestFile.txt Diese Datei wurde geändert: E:\__G__\Neuer Ordner\TestFile.txt

    Wenn ich diese neue Datei umbenenne kommt:
    Dieser Ordner wurde geändert: E:\__G__\Neuer Ordner Diese Datei wurde umbenannt: E:\__G__\Neuer Ordner\TestFileX.txt ===> VON: E:\__G__\Neuer Ordner\TestFile.txt ZU: E:\__G__\Neuer Ordner\TestFileX.txt Dieser Ordner wurde geändert: E:\__G__\Neuer Ordner

    Und zuletzt wenn ich den Ordner umbenenne kommt:
    Dieser Ordner wurde umbenannt: E:\__G__\Neuer OrdnerX ===> VON: E:\__G__\Neuer Ordner ZU: E:\__G__\Neuer OrdnerX

    Dazu brauchst du nur eine kleine Erweiterung inder Prozedur Watcheraction einbauen (siehe Zeile 5-8):

    VB.NET-Quellcode

    1. Private Sub WatcherAction(sender As Object, e As FileSystemEventArgs) Handles DW.Changed, DW.Created, DW.Deleted, DW.Renamed
    2. Dim fi = New FileInfo(e.FullPath)
    3. Dim isDirectory = fi.Attributes = FileAttributes.Directory
    4. Console.WriteLine($"Diese{If(isDirectory, "r Ordner", " Datei")} wurde { GetAction(e.ChangeType)}: " & e.FullPath)
    5. If e.ChangeType = WatcherChangeTypes.Renamed Then
    6. Dim ee = DirectCast(e, RenamedEventArgs)
    7. Console.WriteLine($"===> VON: {ee.OldFullPath} ZU: {ee.FullPath}")
    8. End If
    9. End Sub

    Also - es kommen sämtliche Meldungen...
    @VB1963

    Ne eben nicht. Klar okay, in Zeile 10 meines Codes, wenn ein Ordner umbeannt wird, kommt die Ausgabe "Diese Datei wurde umbenannt...", da sollte man eigentlich dann noch mal unterscheiden zwischen Ordner und Datei. Das verwirrt dich wahrscheinlich ein bisschen...

    Aber darum gings mir jetzt nicht: Ich brauche nämlich keine Benachrichtigung, wenn ein Ordner umbenannt wird, sondern ich brauche Benachrichtigungen (!), dass das Verzeichnis der sich darin befindlichen Dateien sich geändert hat...

    Verstehste?

    @RodFromGermany
    Ich werde das mal probieren. Landet im Endeffekt aber eh in einer WPF-App, also werd ichs auch da mal testen...