Mittels FileSystemWatcher mehrere .txt files gleichzeitig auslesen

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von n0m4d.

    Mittels FileSystemWatcher mehrere .txt files gleichzeitig auslesen

    Heyho liebe community,

    ich stehe vor folgendem Problem:

    Zurzeit schreibe ich gerade an meine Bac Arbeit, teil dieser ist es ein Programm zu schreiben, welches einen bestimmten Ordner überwacht.
    Fall in diesem Ordner nun ein txt file erstellt wird (Das geschieht durch ein 2. Programm) soll über einen FileWatcher dieses txt file erkannt und ausgelesen werden.
    Das funktioniert so auch schon ganz gut, allerdings mit folgendem Problem:

    Es kommt oft vor, dass sehr viele (>40) files mehr oder weniger GLEICHZEITIG in besagtem Ordner abgelegt werden. (Geht um den Druck von Produktlabeln, dh es werden zB 40 Label gedruckt auf denen
    jeweils 1/40 , 2/40 , 3/40, usw steht) ... daher auch die 40 txt files.
    Nun erkennt mein Programm leider immer nur das erste file, da anscheinend das durchlaufen des Codes länger dauert als das speichern der restlichen 39 files. ;(

    Hat jemand eine Idee wie man dieses Problem umgehen könnte?

    Hier mal mein bisheriger Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Initialisieren des FileSystemWatcher
    2. Private Sub main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. trigger.Path = "Z:\Labelprint\Temp"
    4. trigger.NotifyFilter = NotifyFilters.LastWrite
    5. trigger.IncludeSubdirectories = False
    6. trigger.Filter = "*.txt"
    7. End Sub
    8. 'File wird geändert oder erstellt:
    9. Private Sub trigger_changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles trigger.Changed
    10. Dim temp As String = ""
    11. Dim sFile As String = ""
    12. Dim watcher As System.IO.FileSystemWatcher = sender
    13. If startstop = True Then 'Hilfsvariable
    14. watcher.EnableRaisingEvents = False 'Starten
    15. '-------------------------------------------------------------------------------------------- Events die ein Speichern des txt files auslöst
    16. Nice = New NiceApp 'Commando für das Druckprogramm
    17. temp = e.FullPath.ToString 'Hilfsvariable, vollständiger Pfad + Dateiname
    18. sFile = Mid(temp, 41, Len(temp)) 'Abspalten des dateinamen vom Pfadnamen (Für Unterprozeduren)
    19. ListBox1.Items.Add("Trigger gestartet am: " & Date.Now & " um " & TimeOfDay)
    20. Call check_Printjobs(Nice, sFile) 'Sub routine die die Einträge im txt file verarbeitet und an die Drucker schickt
    21. '--------------------------------------------------------------------------------------------
    22. watcher.EnableRaisingEvents = True 'Beenden
    23. Else
    24. Exit Sub
    25. End If
    26. End Sub



    Wie gesagt, mit nur einem file funktioniert das Programm wunderbar, ordnet passende Werte zu und Druckt das Label.
    Wenn aber nun 2 oder mehr files gleichzeitig gespeichert werden spricht es nur auf das erste an. :cursing:
    Ich habe auch schon probiert die Zeilen:

    watcher.EnableRaisingEvents = True bzw false zu löschen, bekomme dann allerdings beim speichern eines txt files 2 mal den FileWatcher aktiviert :/

    Für eure Hilfe schon mal einen ganz Großen Dank :love:
    LG
    Warum setzt du EnableRaisingEvents auf False? Ich kenn den FileSystemWatcher (noch) nicht, aber ich kann mir vorstellen, dass dies das Problem ist. Lass es einfach auf True, damit die restlichen in der Zwischenzeit geschriebenen Dateien ebenfalls als Event in deinem Programm ankommen können.
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    Das hatte den Grund dass dann das file 2-3 mal als "gespeichert" erkannt wird und so auch 2-3 mal die Druckroutine aufruft.
    Werde das aber noch mal gründlich austesten.

    Also kurz und knackig:

    setze ich watcher.EnableRaisingEvents aus false liest er nur eine Datei von vielen ein

    setze ich watcher.EnableRaisingEvents NICHT auf false liest er zwar alle ein, aber eben auch mehrmals die gleichen :/

    lg
    @n0m4d:: Ein paar Anmerkungen:
    1. Nutze das Created-Event, das gibt es pro Datei genau ein Mal.
    2. wie @Arby: sagt: Schalte die Events nicht aus, dann redet Dein Trigger auch mit Dir.
    3. Dreh diese If-Logik um: If startstop = True Then 'Hilfsvariable
    4. Statt der Variable watcher kannst Du wegen Handles trigger.Changed auch gleich trigger verwenden.
    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!
    Hab mir jetzt die FileSystemWatcher-Klasse doch nochmal genauer angesehen.

    Folgende Problemquellen fallen mir in dem Zusammenhang auf:

    1. Das Created-Event wird pro Datei zwar nur einmal ausgelöst, allerdings in dem Moment, wo die Datei erzeugt wird. Ich bin nicht sicher, ob sichergestellt ist, dass man in exakt diesem Moment schon lesend auf die Datei zugreifen kann, sprich, ob es vllt. möglich ist, dass eine zum Schreiben exklusiv geöffnete Datei zu diesem Zeitpunkt noch nicht wieder geschlossen wurde. Dann könnte der Zugriff darauf nämlich fehlschlagen.

    2. Das Changed-Event wird jedesmal aufgerufen, wenn eine Datei im überwachten Ordner geändert wird. Wenn also im vorliegenden Fall das Event pro Datei mehrmals auslöst, kann das ein Zeichen dafür sein, dass das Programm, das die Datei erzeugt, diese mehrmals schreibend anfasst - wie oder warum auch immer. Sollte bei diesen mehrfachen Schreibzugriffen tatsächlich auch der Inhalt effektiv geändert werden, ist es vermutlich im Sinne des Erfinders, dass der Trigger nur die finale Dateiversion, also die nach dem letzten Schreibzugriff, verarbeitet.

    Sollte ich damit richtig liegen, wäre es vermutlich sinnvoller, die Datei von dem anderen Programm auch erst an einem anderen Ort (z.B. im Temp-Ordner des Users) erzeugen und schreiben zu lassen, und erst wenn sie ihren endgültigen Inhalt(szustand) erreicht hat, sie von dort in das überwachte Verzeichnis zu verschieben - und dann aber auch in Ruhe zu lassen.
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    Erstmal vielen Dank für die ganzen Tipps!
    Ich bin Begeistert :D

    @RodFromGermany:

    1. Hab mir das created-event angesehen und getestet, bin aber noch zu keine Ergebnis gekommen :/
    2. Habe ich ebenfalls gemacht (Danke hier an euch beide)
    3. Das hätte ich genauer erklären müssen, hängt noch mit einem Start Button zusammen der die ganze Überwacheng erst einmal aktivieren muss -> tut aber nichts zur Sache
    4. Yeah, eine Variable gespart^^

    @Arby:

    Deine Lösung mit dem Temp Ordner ist rein Zufällig genau die Lösung die auch zur Zeit implementiert ist.
    Allerdings habe ich gedacht es reicht auch, das file nur zu speichern und dann zu triggern, was mmn auch gehen muss, anscheinend aber gar nicht so einfach :/

    Ich werde jetzt auf jeden fall mal die Option austesten -> Datei in Temp Ordner erstellen -> nach Abschluss kopieren in anderen Ordner -> Diesen Ordner überwachen und die Datei darin triggern.

    Hier mal mein aktueller Code:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Button "START"
    2. Private Sub start_Click(sender As Object, e As EventArgs) Handles start.Click
    3. startstop = True
    4. Label2.Text = "aktiviert"
    5. Label2.ForeColor = Color.Green
    6. trigger.Path = "Z:\Labelprint" '-----KEIN Temp Ordner mehr
    7. trigger.NotifyFilter = NotifyFilters.CreationTime
    8. trigger.IncludeSubdirectories = False
    9. trigger.Filter = "*.txt"
    10. AddHandler trigger.Created, AddressOf trigger_changed
    11. trigger.EnableRaisingEvents = True
    12. End Sub
    13. Private Sub trigger_changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles trigger.Changed
    14. Dim temp As String = ""
    15. Dim sFile As String = ""
    16. Dim person As String
    17. If startstop = True Then
    18. Nice = New NiceApp
    19. temp = e.FullPath.ToString
    20. sFile = Mid(temp, 41, Len(temp))
    21. ListBox1.Items.Add("Trigger gestartet am: " & Date.Now & " um " & TimeOfDay)
    22. Call check_Printjobs(Nice, sFile)
    23. Else
    24. Exit Sub
    25. End If
    26. End Sub



    Kann das nur leider gerade nicht testen, da alles was in diesem Ordner erstellt wird sofort von einem bestehenden Programm erfasst und gedruckt wird^^
    Mal sehen ob ich eine Genehmigung kriege.

    Ganz großes Danke nachmal!
    lg

    n0m4d schrieb:

    von einem bestehenden Programm erfasst und gedruckt wird
    Dann gib ihm einen PDF-Drucker
    oder
    Nimm ein anderes Verzeichnis zum Testen.
    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!
    OK, nevermind habs jetzt hinbekommen^^

    Überwache jetzt einen zweiten Ordner in den das txt file kopiert wird und es funktioniert wunderbar.

    Hier noch mal der Code, hilft ja vl. irgendwann jemand:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Button "START" , initialisieren des File Triggers
    2. Private Sub start_Click(sender As Object, e As EventArgs) Handles start.Click
    3. startstop = True
    4. Label2.Text = "aktiviert"
    5. Label2.ForeColor = Color.Green
    6. trigger.Path = "T:\temp"
    7. trigger.IncludeSubdirectories = False
    8. trigger.Filter = "*.txt"
    9. AddHandler trigger.Created, AddressOf OnChanged
    10. trigger.EnableRaisingEvents = True
    11. End Sub
    12. 'Handelt den File Trigger
    13. Private Sub OnChanged(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs)
    14. Dim temp As String = ""
    15. Dim sFile As String = ""
    16. Nice = New NiceApp
    17. temp = e.FullPath
    18. sFile = Mid(temp, 9, Len(temp))
    19. Dim Params As Object
    20. Params = ("Trigger gestartet am: " & Date.Now & " um " & TimeOfDay) ' Wird benötigt um Threadübergreifend in eine Listbox zu schreiben.
    21. Me.Invoke(New WriteInListDelegate(AddressOf WriteInList), Params)
    22. Call check_Printjobs(Nice, sFile)
    23. End Sub


    Vielen Dank nochmal an euch für eure Hilfe! Echt ein super Forum hier :D

    lg und schönen Tag noch