none
Ordnerinhalte vergleichen RRS feed

  • Frage

  • Hallo zusammen, ich schreibe momentan an einem Synchronisierungs-Tool. 

    Hier muss ich 2 Ordner miteinander vergleichen. Und zwar befinden sich in beiden Ordnern Fotos. In Ordner A kommen szändig neue Fotos hinzu. Nun möchte ich beide Ordner miteinander vergleichen und nur die Fotos, die in Ordner A sind, aber noch nicht in Ordner B, in den Ordner B kopieren.

    Kann mir hier jemand weiterhelfen?

    Mfg

    RK

    Montag, 17. März 2014 14:38

Antworten

  • Das funktioniert aber nicht mit .NET 4.5. VS 2010 ist auf 4.0 beschränkt.

    Ich habe es aber nochmal bei mir getestet. Yield wird auch unter VS 2012 SP1 nicht unterstützt. Hier hast du nochmal meinen umgeschriebenen Code:

    Sub Main()
        Dim pathA = "D:\Test\A"
        Dim pathB = "D:\Test\B"
    
        Dim res = CompareFolders(pathA, pathB)
        For Each file In res
            Dim fldr = New FileInfo(file.Replace(pathA, pathB)).Directory.FullName 'Raplace um "A" durch "B" zu tauschen'
            If Not Directory.Exists(fldr) Then
                Directory.CreateDirectory(fldr) 'Ordner erstellen falls nicht vorhanden'
            End If
            System.IO.File.Copy(file, file.Replace(pathA, pathB)) 'Datei kopieren'
        Next
    
    End Sub
    
    ''' <summary>'
    ''' Vergleicht die Dateien in A mit den Dateien in B und gibt eine Liste von Dateinamen zurück, die in A, aber nicht in B enthalten sind.'
    ''' </summary>'
    Function CompareFolders(pathA As String, pathB As String) As List(Of String)
        Dim result As New List(Of String)()
        Dim filesA = Directory.GetFiles(pathA) 'Dateien von A auslesen'
        Dim filesB As String() 'Wenn b nicht existiert, dann wird ein leeres Array genommen > Alle Dateien werden zurück gegeben'
        If Directory.Exists(pathB) Then
            filesB = Directory.GetFiles(pathB)
        Else
            filesB = New String() {} 'Leeres Array'
        End If
    
        For i As Integer = 0 To filesA.Length - 1
            'Nacholgende Abfrage überprüft, ob eine Datei schon vorhanden ist. Ggf. eine bessere Methode zum vergleichen aufbauen'
            If Not filesB.Contains(filesA(i).Replace(pathA, pathB)) Then
                result.Add(filesA(i)) 'Gebe die einzelne Datei zurück, die in B nicht vorhanden ist'
            End If
        Next
    
        For Each folder In Directory.GetDirectories(pathA)
            For Each res In CompareFolders(folder, folder.Replace(pathA, pathB)) 'Rekursiv für jeden Ordner aufrufen'
                result.Add(res) 'Die einzelnen Ergebnisse des rekursiven Aufrufs zurück geben'
            Next
        Next
        Return result
    End Function
    Den konnte ich problemlos im VS 2012 SP1 unter .NET 4.0 kompilieren.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    • Als Antwort markiert Robbo1984 Dienstag, 18. März 2014 07:00
    Montag, 17. März 2014 21:05
    Moderator

Alle Antworten

  • Hi Robbo1984,

    zu deiner Frage. Ja hier können, dir sicher einige Helfen.

    Zum Rest, ein bischen Eigenleistung, wo ist den genau dein Problem.

    Bestimmen des Ordner inhalts, abgleich der Daten oder das Kopieren?

    Gib einfach mal an was du schon hast, gegebenen fals Quellcode. Und beschreib dann dein Problem möglichst genau.

    MFG
    Björn

    Montag, 17. März 2014 14:53
  • Hallo,
    zunächst musst du unterscheiden, wie die Dateien verglichen werden sollen:

    1. Nur anhand der Namen. i.d.R. sollte das ausreichen. Dabei musst du dir aber zu 100% sicher sein, das 2 Dateien niemals gleich heißen. (Im selben Ordner)
    2. Du vergleichst wirklich die Dateiinhalte. Das ist deutlich aufwendigr und dauert um ein vielfaches länger als 1.

    Der Einfachheit halber ist nachfolgendes Beispiel mit der Methode von 1. geschrieben:

    Sub Main()
        Dim pathA = "D:\Test\A"
        Dim pathB = "D:\Test\B"
    
        Dim res = CompareFolders(pathA, pathB).ToList() 'ToList() ist nur fürs Debuggen, damit man im ToolTip auch eine Auflistung finden kann'
        For Each file In res
            Dim fldr = New FileInfo(file.Replace(pathA, pathB)).Directory.FullName'Raplace um "A" durch "B" zu tauschen'
            If Not Directory.Exists(fldr) Then
                Directory.CreateDirectory(fldr) 'Ordner erstellen falls nicht vorhanden'
            End If
            System.IO.File.Copy(file, file.Replace(pathA, pathB))'Datei kopieren'
        Next
    
    End Sub
    
    ''' <summary>'
    ''' Vergleicht die Dateien in A mit den Dateien in B und gibt eine Liste von Dateinamen zurück, die in A, aber nicht in B enthalten sind.'
    ''' </summary>'
    Iterator Function CompareFolders(pathA As String, pathB As String) As IEnumerable(Of String)
        Dim filesA = Directory.GetFiles(pathA) 'Dateien von A auslesen'
        Dim filesB As String() 'Wenn b nicht existiert, dann wird ein leeres Array genommen > Alle Dateien werden zurück gegeben'
        If Directory.Exists(pathB) Then
            filesB = Directory.GetFiles(pathB)
        Else
            filesB = New String() {}'Leeres Array'
        End If
    
        For i As Integer = 0 To filesA.Length - 1
            'Nacholgende Abfrage überprüft, ob eine Datei schon vorhanden ist. Ggf. eine bessere Methode zum vergleichen aufbauen'
            If Not filesB.Contains(filesA(i).Replace(pathA, pathB)) Then
                Yield filesA(i) 'Gebe die einzelne Datei zurück, die in B nicht vorhanden ist'
            End If
        Next
    
        For Each folder In Directory.GetDirectories(pathA)
            For Each res In CompareFolders(folder, folder.Replace(pathA, pathB)) 'Rekursiv für jeden Ordner aufrufen'
                Yield res 'Die einzelnen Ergebnisse des rekursiven Aufrufs zurück geben'
            Next
        Next
    End Function
    Ich habe das Beispiel nicht sehr ausführlich getestet und man kann es noch um Einiges effektivieren. Aber es sollte dir einen Ansatz bieten. Um die Dateien Byte für Byte zu vergleichen, findest du hier eine Möglichkeit.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.


    Montag, 17. März 2014 15:11
    Moderator
  • mein Problem ist: ich hole mir die dateien aus ordner A und auch die aus Ordner B. in A findet er 6 Dateien und in B nur 3. Ist auch vollkommen richtig so. aber wie sage ich ihm jetzt dass er diese 3 kopieren soll, die nicht vorhanden sind. Nutze ich obene ge
     Private Sub SyncWundendokumente()
    
            Dim pathA = "C:\Users\Public.....PicsA"
            Dim pathB = "C:\Users\Public.....PicsB"
    
            Dim filesA() As String
            Dim filesB() As String
    
            If IO.Directory.Exists(pathA) Then
                'Alle Dateien aus dem Ordner auslesen
                filesA = IO.Directory.GetFiles(pathA)
    
                If IO.Directory.Exists(pathB) Then
                    filesB = Directory.GetFiles(pathB)
    
                    For i As Integer = 0 To filesA.Length - 1
                      
    
                        For Each File In filesA
                            If Not filesB.Contains(filesA(i).Replace(pathA, pathB)) Then
    
                            End If
    
                        Next
                    Next
                End If
            End If
    
        End Sub

    gebenes Beispiel entstehen nur Fehler....
    Montag, 17. März 2014 20:01
  • Was sind denn das für Fehler? Poste diese bitte immer Vollständig mit Zeilenangabe.
    Fehlt dir vielleicht noch folgender Namespace?

    Imports System.IO
    In meinem Code oben gehe ich alle Dateien in einem Ordner durch. Sobald eine Datei in B fehlt, wird diese mittels Yield zurück gegeben. Am Ende rufst sich die Methode rekursiv mit allen Unterordnern auf.

    Nach dem Aufruf der Methode erhält man eine Auflistung von Fehlenden Dateien. Diese kopiere ich dann in einer Schleife. (Zuvor wird ggf. der beinhaltende Ordner erstellt).

    Deinen Codeschnippsel verstehe ich nun allerdings nicht so ganz. Es scheint auf meinem Code zu bassieren, aber alles zusammen in einer Methode. Das kann so aber nicht funktionieren, da sich CompareFolders selbst aufruft um die Unterordner zu vergleichen. Es muss also eine extra Methode dafür geben.
    Versuche meinen Code zu verstehen. Erstelle dir einfach mal eine kleine Ordnerhierachie die du übertragen möchtest. Dann kannst du mit F11 Zeile für Zeile ausführen und so den Ablauf des ganzen verstehen. Wenn du auf eine Variable zeigst, erfährst du deren Inhalt.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Montag, 17. März 2014 20:11
    Moderator
  • da wären wir schon bei einem fehler... yield wird nicht erkannt... imports system.IO ist importiert... zudem wird comparefolders nicht erkannt
    Montag, 17. März 2014 20:16
  • Zu CompareFolders wird nichts erkannt:
    Wenn du meinen COde nur kopierst ohne ihn zu verstehen kann es nicht funktionieren. CompareFolders ist die Funktion, in der sie sich selbst aufrufst um die Unterordner zu vergleichen.

    Zum Yield wird nicht erkannt:
    Return würde nur ein Element zurück geben. Yield dagegen gibt ein Element einer Liste zurück.
    Da du meinen Code nur kopiert hast: Eine Sub kann nichts zurück geben, im Gegensatz zu einer Function.

    Ich für meinen Teil habe alles mittlerweile 2mal erklärt. Verstehe meinen Code, dann helfe ich dir auch gerne weiter.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Montag, 17. März 2014 20:28
    Moderator
  • ich verstehe den Code soweit . Aber mir muss doch irgendein IMPORT fehlen, da nur dieses Yield nicht erkannt wird und ich demnach die fehlermeldung bekomme dass yield nicht deklariert ist.
    Montag, 17. März 2014 20:39
  • Hi,

    welche .NET Frameworkversion setzt Du für dieses Projekt ein? Welches .NET Framework Profil? (Falls Client Profile, ändere das mal auf die normale Variante)


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Montag, 17. März 2014 20:43
    Moderator
  • .NET Framework 4.5
    Montag, 17. März 2014 20:46
  • Was benutzt du denn für ein VS? Soweit ich weiß ist Yield erst ab VS 2010 SP1 verfügbar.

    Alternativ kannst du auch alle Dateipfade zu einer List(Of String) hinzufügen und dann alles gebündelt zurück geben. So sparrst du dir das Yield. Das ist zwar nicht so schön wie ich finde, aber die einzige Möglichkeit in älteren VB.NET's.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Montag, 17. März 2014 20:47
    Moderator
  • ich nutze VB 2010 SP1... alles frisch installiert.....
    Montag, 17. März 2014 20:55
  • Das funktioniert aber nicht mit .NET 4.5. VS 2010 ist auf 4.0 beschränkt.

    Ich habe es aber nochmal bei mir getestet. Yield wird auch unter VS 2012 SP1 nicht unterstützt. Hier hast du nochmal meinen umgeschriebenen Code:

    Sub Main()
        Dim pathA = "D:\Test\A"
        Dim pathB = "D:\Test\B"
    
        Dim res = CompareFolders(pathA, pathB)
        For Each file In res
            Dim fldr = New FileInfo(file.Replace(pathA, pathB)).Directory.FullName 'Raplace um "A" durch "B" zu tauschen'
            If Not Directory.Exists(fldr) Then
                Directory.CreateDirectory(fldr) 'Ordner erstellen falls nicht vorhanden'
            End If
            System.IO.File.Copy(file, file.Replace(pathA, pathB)) 'Datei kopieren'
        Next
    
    End Sub
    
    ''' <summary>'
    ''' Vergleicht die Dateien in A mit den Dateien in B und gibt eine Liste von Dateinamen zurück, die in A, aber nicht in B enthalten sind.'
    ''' </summary>'
    Function CompareFolders(pathA As String, pathB As String) As List(Of String)
        Dim result As New List(Of String)()
        Dim filesA = Directory.GetFiles(pathA) 'Dateien von A auslesen'
        Dim filesB As String() 'Wenn b nicht existiert, dann wird ein leeres Array genommen > Alle Dateien werden zurück gegeben'
        If Directory.Exists(pathB) Then
            filesB = Directory.GetFiles(pathB)
        Else
            filesB = New String() {} 'Leeres Array'
        End If
    
        For i As Integer = 0 To filesA.Length - 1
            'Nacholgende Abfrage überprüft, ob eine Datei schon vorhanden ist. Ggf. eine bessere Methode zum vergleichen aufbauen'
            If Not filesB.Contains(filesA(i).Replace(pathA, pathB)) Then
                result.Add(filesA(i)) 'Gebe die einzelne Datei zurück, die in B nicht vorhanden ist'
            End If
        Next
    
        For Each folder In Directory.GetDirectories(pathA)
            For Each res In CompareFolders(folder, folder.Replace(pathA, pathB)) 'Rekursiv für jeden Ordner aufrufen'
                result.Add(res) 'Die einzelnen Ergebnisse des rekursiven Aufrufs zurück geben'
            Next
        Next
        Return result
    End Function
    Den konnte ich problemlos im VS 2012 SP1 unter .NET 4.0 kompilieren.


    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    • Als Antwort markiert Robbo1984 Dienstag, 18. März 2014 07:00
    Montag, 17. März 2014 21:05
    Moderator
  • Super... jetzt funktioniert es ohne Probleme.... Dankeschön... 
    Montag, 17. März 2014 21:23