Datensychronisation zwischen 3 Pfaden

  • VB.NET

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von Andinistrator.

    Datensychronisation zwischen 3 Pfaden

    Guten Morgen zusammen,

    für eine Synchronisation habe ich mir folgenden Code erstellt:
    SyncA vergleicht Ordner1 und 2
    Synch B vergleicht Ordber2 und 3
    (in eine Listbox lasse ich das Ergebnis anzeigen)

    Ich hänge leider an zwei Punkten:
    - Es sollen z.B. nur *.txt Dateien abgeglichen werden
    - Z.b. kann Ordner3 mal "offline" sein, d.h. hier bricht das Programm ab. Statt dessen möchte ich max. in einer Textbox "Ordner3 nicht erreichbar" schreiben, aber das Programm soll weiterlaufen

    Hat bitte jemand einen Tipp für mich? Vielen Dank!

    VB.NET-Quellcode

    1. Private Sub SyncA()
    2. Dim Vergleich1 = System.IO.Directory.GetFiles(TextBox1.Text)
    3. Dim Vergleich2 = System.IO.Directory.GetFiles(TextBox2.Text)
    4. For Each Datei1 In Vergleich1
    5. Dim dtname = Datei1.Substring(TextBox1.Text.Length)
    6. If Not System.IO.File.Exists(TextBox2.Text & dtname) Then
    7. System.IO.File.Copy(Datei1, TextBox2.Text & dtname)
    8. ListBox1.Items.Add(Now & dtname)
    9. End If
    10. If ListBox1.Items.Count > 39 Then
    11. ListBox1.Items.Clear()
    12. ListBox1.Items.Add(Now & dtname)
    13. End If
    14. Next
    15. For Each Datei2 In Vergleich2
    16. Dim dtname = Datei2.Substring(TextBox2.Text.Length)
    17. If Not System.IO.File.Exists(TextBox1.Text & dtname) Then
    18. System.IO.File.Delete(Datei2)
    19. End If
    20. Next
    21. End Sub
    22. Private Sub SyncB()
    23. Dim Vergleich2 = System.IO.Directory.GetFiles(TextBox2.Text)
    24. Dim Vergleich3 = System.IO.Directory.GetFiles(TextBox3.Text)
    25. For Each Datei2 In Vergleich2
    26. Dim dtname = Datei2.Substring(TextBox2.Text.Length)
    27. If Not System.IO.File.Exists(TextBox3.Text & dtname) Then
    28. System.IO.File.Copy(Datei2, TextBox3.Text & dtname)
    29. End If
    30. Next
    31. For Each Datei3 In Vergleich3
    32. Dim dtname = Datei3.Substring(TextBox3.Text.Length)
    33. If Not System.IO.File.Exists(TextBox2.Text & dtname) Then
    34. System.IO.File.Delete(Datei3)
    35. End If
    36. Next
    37. End Sub
    Hat bitte jemand einen Tipp für mich? Vielen Dank!
    Nur zu 1) - das ist schon Stoff genug erstmal:

    1) Lerne, was "Überladung" bedeutet. Grundlagen: Fachbegriffe
    2) Lerne den ObjectBrowser zu benutzen. VisualStudio richtig nutzen (Google ist nicht deine Mami)
    3) Guck dir im ObjectBrowser die Überladungen von Directory.GetFiles() an - es sind welche dabei, die nehmen auch einen pattern an, wie etwa *.txt
    Danke - damit komme ich leider nicht weiter. Was mir dazu geholfen und sehr gut beschrieben ist, die *.txt Dateien in eine Listbox zu schreiben:
    vbarchiv.net/tipps/tipp_617-al…ners-ermitteln-vbnet.html

    Das wollte ich umbasteln in eine Kopierfunktion, komme jedoch ins stolpern:

    VB.NET-Quellcode

    1. Private Sub SyncA(ByVal sender As System.Object, _
    2. ByVal e As System.EventArgs) Handles Timer1.Tick
    3. ' Verzeichnis, dessen Dateien ermittelt werden sollen
    4. Dim sPath As String
    5. sPath = TextBox1.Text
    6. Dim sPath2 As String
    7. sPath2 = TextBox2.Text
    8. ' Directory-Object erstellen
    9. Dim oDir As New System.IO.DirectoryInfo(sPath)
    10. ' nur TXT-Dateien ...
    11. Dim oFiles As System.IO.FileInfo() = oDir.GetFiles("*.txt")
    12. ' Datei-Array durchlaufen und in
    13. Dim oFile As System.IO.FileInfo
    14. For Each oFile In oFiles
    15. If Not System.IO.File.Exists(sPath2) Then
    16. System.IO.File.Copy(oFile.Name, sPath2)
    17. End If
    18. Next
    19. End Sub



    Das ist schonmal sehr schön - die Funktion kann ich gut gebrauchen :) ! So bleibt das Programm nicht ständig hängen. Dankeschön!

    Jetzt muss ich aber meine Kopierfunktion prüfen, warum der die *.txt Datei nicht nach sPath2 kopiert, wenn diese nicht in sPath2 existiert.

    VB.NET-Quellcode

    1. Private Sub SyncA(ByVal sender As System.Object, _
    2. ByVal e As System.EventArgs) Handles Timer1.Tick
    3. Try
    4. ' Verzeichnis, dessen Dateien ermittelt werden sollen
    5. Dim sPath As String
    6. sPath = TextBox1.Text
    7. Dim sPath2 As String
    8. sPath2 = TextBox2.Text
    9. ' Directory-Object erstellen
    10. Dim oDir As New System.IO.DirectoryInfo(sPath)
    11. ' nur TXT-Dateien ...
    12. Dim oFiles As System.IO.FileInfo() = oDir.GetFiles("*.txt")
    13. ' Datei-Array durchlaufen und in
    14. Dim oFile As System.IO.FileInfo
    15. For Each oFile In oFiles
    16. If Not System.IO.File.Exists(sPath2) Then
    17. System.IO.File.Copy(oFile.Name, sPath2)
    18. End If
    19. Next
    20. Catch ex As Exception
    21. Dim Fehler As String
    22. Fehler = " nicht erreichbar"
    23. ListBox2.Items.Clear()
    24. ListBox2.Items.Add(Fehler)
    25. End Try
    26. End Sub
    ich rate von dem TryCatch ab.
    Dein Prog funktioniert nicht, weil es Fehler enthält, die du beheben musst.
    Einen TryCatch behebt nicht den Fehler, sondern der bleibt natürlich nachwievor drin.
    Nur der TryCatch erschwert dir das Debuggen.
    Hast du den Fehler behoben, brauchst du den TryCatch auch nicht mehr.

    Der Fehler liegt in zeile#23, denn was du als QuellPfad angibst ist kein vollständiger Pfad, sondern nur der Name der Datei.

    Cheffboss schrieb:

    Try Catch
    What?
    Fehler verschleiern statt sie zu vermeiden?

    Andinistrator schrieb:

    So bleibt das Programm nicht ständig hängen.
    Kann es sein, dass Du alle Quelldateien auf eine einzige Zieldatei schreibst? Es ist möglich, dass Du die nächste Datei bereits kopieren willst, bevor die alte Kopieranweisung völlig fertig ist, weil ja die Zieldatei identisch ist.
    Was genau willst Du eigentlich kopieren?
    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!
    @ Cheffboss
    Also der Try Catch hilft mir z.B. auch, weil ich einen Button hab, wo der User den Inhalt des Pfades abfragen kann. Ist der Pfad nicht verfügbar, kann ich nun einen Fehlertext auswerfen, ohne dass das Programm abschmiert.

    @ RodFromGermany
    Ja - das Programm soll quasi Ordner1 und 2 abgleichen, d.h. das Programm schaut ob die *.txt Datei bereits in Ordner2 drin ist, wenn nicht, dann soll es die *.txt Datei dort rein kopieren. Wenn die Datei schon da drin ist, soll es nichts machen. (Für mein Stadium reicht es den Dateinamen abzufragen, also ohne Datum der Datei etc.)
    Daher wirst du bestimmt Recht haben, ich weiß nicht wie ich es lösen kann. In meinem obersten Beitrag hatte ich gehofft, man muss nur irgendwo ein *.txt einfügen und dann passt es. Nun weiß ich, dass dies nicht so einfach ist. ?(
    Ich bekomme jetzt eine andere Meldung:

    Ein Ausnahmefehler des Typs "System.IO.IOException" ist in mscorlib.dll aufgetreten.
    Zusätzliche Informationen: Die Zieldatei "C:\Ordner2" ist keine Datei, sondern ein Verzeichnis.


    Ich hab das mal etwas eingedeutscht:
    Quelle = C:\Ordner1
    Ablage = C:\Ordner2

    VB.NET-Quellcode

    1. Private Sub SyncA(ByVal sender As System.Object, _
    2. ByVal e As System.EventArgs) Handles Timer1.Tick
    3. Dim Quelle As String
    4. Dim Ablage As String
    5. Quelle = TextBox1.Text
    6. Ablage = TextBox2.Text
    7. Dim oDir As New System.IO.DirectoryInfo(Quelle)
    8. Dim oFiles As System.IO.FileInfo() = oDir.GetFiles("*.txt")
    9. Dim oFile As System.IO.FileInfo
    10. For Each oFile In oFiles
    11. If Not System.IO.File.Exists(Ablage) Then
    12. System.IO.File.Copy(oFile.FullName, Ablage)
    13. End If
    14. Next
    15. End Sub

    Andinistrator schrieb:

    ich weiß nicht wie ich es lösen kann.
    Lerne zu debuggen.
    Setze einen Haltepunkt in die Routine und arbeite sie Zeile für Zeile durch.
    Vergleiche den inhalt von Variablen mit den Werten, von denen Du meinst, dass sie drin stehen sollen.
    Wenn Du eine Abweichung gefunden hast, hast Du einen Fehler gefunden. Gugst Du hier.
    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!
    @ ErfinderDesRades
    Ich finde es eigentlich ganz hilfreich zu sehen, wie es richtig geht, da meine Entwurf die Option(en) gar nicht bietet. Mir hilft es jedenfalls weiter, verschieden Funktionen kennenzulernen. Eine Frage habe ich noch, damit mein Entwurf vollständig berichtigt ist:

    Im Code habe ich ein ", true" hinzugefügt, damit die Datei - falls vorhanden - überschrieben wird. Wie muss es aber nun richtig aussehen, wenn ich Ordner1 und 2 vergleichen möchte und dabei jede *.txt Datei welche nicht in Ordner 1 ist, auch weiterhin aus Ordner2 lösche?

    VB.NET-Quellcode

    1. Private Sub SyncA(ByVal sender As System.Object, _
    2. ByVal e As System.EventArgs) Handles Timer1.Tick
    3. Dim Quelle As String
    4. Dim Ablage As String
    5. Quelle = TextBox1.Text
    6. Ablage = TextBox2.Text
    7. Dim oDir As New System.IO.DirectoryInfo(Quelle)
    8. Dim oFiles As System.IO.FileInfo() = oDir.GetFiles("*.txt")
    9. Dim oFile As System.IO.FileInfo
    10. For Each oFile In oFiles
    11. If Not System.IO.File.Exists(Ablage) Then
    12. System.IO.File.Copy(oFile.FullName, System.IO.Path.Combine(Ablage, oFile.Name), True)
    13. End If
    14. Next
    15. End Sub

    VB.NET-Quellcode

    1. Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
    2. Sync(New DirectoryInfo(TextBox1.Text), New DirectoryInfo(TextBox2.Text))
    3. End Sub
    4. Private Sub Sync(di1 As DirectoryInfo, di2 As DirectoryInfo)
    5. Dim fi1s = di1.GetFiles("*.txt")
    6. Dim fi2s = di2.GetFiles("*.txt")
    7. Dim keySelector As Func(Of FileInfo, Integer) = Function(fi) fi.FullName.GetHashCode
    8. With DifferenceAnalize(fi1s, fi2s, keySelector, keySelector)
    9. For Each fi In .List2_Only
    10. fi.Delete()
    11. Next
    12. For Each fi In .List1_Only
    13. File.Copy(fi.FullName, Path.Combine(di2.FullName, fi.Name))
    14. Next
    15. End With
    16. End Sub
    17. Public Function DifferenceAnalize(Of T1, T2)(lst1 As IEnumerable(Of T1), lst2 As IEnumerable(Of T2), Optional keySelector1 As Func(Of T1, Integer) = Nothing, Optional keySelector2 As Func(Of T2, Integer) = Nothing) As DifferenceResult(Of T1, T2)
    18. If keySelector1 Is Nothing Then keySelector1 = Function(o As T1) o.GetHashCode
    19. If keySelector2 Is Nothing Then keySelector2 = Function(o As T2) o.GetHashCode
    20. Dim dic1 = New Dictionary(Of Integer, T1)
    21. With DifferenceAnalize
    22. .List2_Only = New List(Of T2)
    23. .Mappings = New List(Of Tuple(Of T1, T2))
    24. Dim itm1 As T1 = Nothing
    25. For Each itm1 In lst1
    26. dic1.Add(keySelector1(itm1), itm1)
    27. Next
    28. For Each itm2 In lst2
    29. Dim key = keySelector2(itm2)
    30. If dic1.TryGetValue(key, itm1) Then
    31. .Mappings.Add(Tuple.Create(itm1, itm2))
    32. dic1.Remove(key)
    33. Else
    34. .List2_Only.Add(itm2)
    35. End If
    36. Next
    37. .List1_Only = dic1.Values.ToList
    38. End With
    39. End Function
    40. Public Structure DifferenceResult(Of T1, T2)
    41. Public List1_Only As List(Of T1)
    42. Public List2_Only As List(Of T2)
    43. Public Mappings As List(Of Tuple(Of T1, T2))
    44. End Structure
    Guten Morgen, vielen Dank! Das muss ich erstmal "studieren". Ich glaube das richtige Forum gefunden zu haben, so macht es wirklich Spaß bei den Antworten :rolleyes: .

    Eine kleine Ergänzung:

    VB.NET-Quellcode

    1. Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
    2. Sync(New DirectoryInfo(TextBox1.Text), New DirectoryInfo(TextBox2.Text))
    3. End Sub
    4. Private Sub Sync(di1 As DirectoryInfo, di2 As DirectoryInfo)
    5. '...

    Andinistrator schrieb:

    Eine kleine Ergänzung:
    Es ist suboptimal, das ganze Timer-gesteuert zu machen.
    Wenn Du eine Pizza bestellst, gehst Du auch nicht alle 3 Minuten zur Tür und siehst nach, ob der Pizzabote da ist, Du wartest, bis er klingelt.
    Also:
    Schmeiß das ganzen Timer-Zeugs raus und bediene Dich eines FileSystemWatchers.
    Einfach im Designer auf die GUI ziehen und konfigurieren. Gugst Du hier.
    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!
    v.a. probiers erstmal aus, obs in deinem Sinne arbeitet.

    Dann kommen wir wieder bei post#2 raus, der dir nämlich ein Instrumentarium gibt, mit dem du die Funktionsweise untersuchen kannst. Setze dazu Haltepunkte, und step im Einzelschritt durch, beobachte dabei die Variablen im Lokalfenster oder erstell Überwachungen für alles, was dein Interesse weckt.
    @ RodFromGermany
    Du hast vollkommen Recht, die Option ist selbstverständlich die bessere Variante in dem Fall. Ich schau mit das Thema an, ggf. mache hier hierzu ein neues Thema auf.

    @ErfinderDesRades
    Ja - hier werde ich üben. Vielen Dank!