C# Verzeichnisse Synchronisieren

ali7566

Lieutenant
Registriert
Feb. 2007
Beiträge
938
Hallo leute,

ich beschäftige mich gerade mit einer Aufgabe aus dem Studium bei der es darum geht zwei verzeichnisse (Quell und Zielverzeichnis) zu synchronisieren, wenn a) die Datei aus der Quelle ein neueres datum hat als ziel, b) wenn das Datum der Datei aus der Quelle neuer ist als der vom Zielverzeichnis.

Den Code habe ich soweit schon fertig, jedoch bekomme ich noch einige exceptions rausgehauen mit denen ich auch nach langem experementieren zu keiner Lösung kommen konnte.

Ich habe im Prinzip einen Button "Kopieren" der die Synchronisation anstoßt. Wenn die Verzeichnisse synchron sind wird logischweise nichts gemacht.

Hier mal zum Code:

Code:
//Methode prüft ob es sich um eine Datei oder eine Ordner handelt
 public Boolean verzeichOrDatei(string a) 

        { 
            if(0 == (File.GetAttributes(a) & FileAttributes.Directory))
            {
                return true; // true steht für eine Datei
            }

            else
            {
                return false; // false steht für einen Ordner
            }
        
        }
        // wenn es sich um einen Ordner handelt wird dieser mit der Methode erstellt bzw. Kopiert
        public void copyDirectory(string quellpfad, string zielpfad)
        {
            DirectoryInfo qp= new DirectoryInfo(quellpfad);

            if(!Directory.Exists(zielpfad))
            {
                Directory.CreateDirectory(zielpfad);
            }

            foreach(DirectoryInfo a in qp.GetDirectories())
            {
                copyDirectory(a.FullName, zielpfad+"\\"+a.FullName);
            }

            foreach (FileInfo f in qp.GetFiles())
            {
                f.CopyTo(zielpfad + "\\" + f.Name, true);
            }

        
        
        }
         // Die Methode die sich ums Synchronisieren kümmert
        private void btnCopy_Click(object sender, EventArgs e)
        {
            FileInfo dirQ,dirZ; // FileInfo Objekte für Quelle und Ziel
            string[] namenQ, namenZ;
            DateTime[] zeitDatenQ, zeitDatenZ;
            Boolean a;
            string [] substring, substring2;

            // Informationen von Quelle und Ziel wird an die Arrays übergeben
            namenQ = Directory.GetFileSystemEntries(txtQuelle.Text);
            namenZ = Directory.GetFileSystemEntries(txtZiel.Text);

            zeitDatenQ = new DateTime[namenQ.Length];
            zeitDatenZ = new DateTime[namenZ.Length];

            
                for (int i = 0; i < namenQ.Length; i++)
                {
                    dirQ = new FileInfo(namenQ[i]);
                    dirZ = new FileInfo(namenZ[i]);
                    
                    // der Zeitpunkt des letztens schreibvorgang wird ermittelt
                    zeitDatenQ[i] = Directory.GetLastWriteTime(dirQ.DirectoryName);
                    zeitDatenZ[i] = Directory.GetLastWriteTime(dirZ.DirectoryName);

                    // es wird gesplittet um die Datei oder Verzeichnisnamen zu erhalten
                    substring = namenQ[i].Split('\\');
                    substring2 = namenZ[i].Split('\\');

                    if (zeitDatenQ[i] > zeitDatenZ[i]) // ob quelle neuer ist als Ziel
                    {
                        a = verzeichOrDatei(namenQ[i]); // Methode prüft ob datei oder Verzeichnis

                        if (a == true) //Datei
                        {
                            try
                            {
                                // Wenn datei nicht existiert dann kopieren
                                File.Copy(namenQ[i], namenZ[i]); 
                            }
                            catch (Exception ex)
                            {
                                // wenn datei exisitert wird überschrieben
                                MessageBox.Show(ex.ToString());
                                File.Replace(namenQ[i], namenZ[i], "C:\\Users\\ali-g\\Desktop\\sicherung\\"+substring[substring.Length-1]);
                            }
                        }

                        else if (a == false) //Verzeichnis
                        {
                           // Bei einem Verzeichnis wird erzeugt oder erstellt 
                           copyDirectory(namenQ[i], namenZ[i]);
                        }
                    }
                    //Es wird geprüft ob der Dateiname von Quelle gleich von Ziel ist
                    if (substring[substring.Length-1] != substring2[substring2.Length-1])
                    {
                        // prüfen ob Verzeichnis oder Datei
                        a = verzeichOrDatei(namenQ[i]);

                        if (a == true) // Datei 
                        {
                            try
                            {
                                File.Copy(namenQ[i], namenZ[i]);
                            }
                            catch(Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                                File.Replace(namenQ[i], namenZ[i], "C:\\Users\\ali-g\\Desktop\\sicherung\\" + substring[substring.Length - 1]);
                            }

                            
                        }

                        else if (a == false) // Verzeichnis
                        {
                            copyDirectory(namenQ[i], namenZ[i]);
                        }
                    }


                }

            }

Das Problem ist das es an der Stelle wo ich File.Copy() oder File.Replace() verwende es gehörig knallt.
Warum das so ist weiß ich jedoch nicht, die Exceptions sagen mir nicht viel.

Ich befürchte das auch logische Fehler sich eingeschlischen haben.

edit: Die Exceptions sind bei Copy oder Replace, sind IOExceptions die sagen das die datei nicht überschrieben werden konnte.

Wer kann mir helfen ?
 
Zuletzt bearbeitet:
Hier die Exceptions:
 

Anhänge

  • Exception.JPG
    Exception.JPG
    40,1 KB · Aufrufe: 408
  • Exception2.JPG
    Exception2.JPG
    77,6 KB · Aufrufe: 397
Bei File.Copy kannst du als dritten Parameter noch "true" übergeben, damit wird ein Überschreiben einer bereits vorhandenen Datei erzwungen.

Was ich sonst noch "interessant" an deinem Code finde, du greifst auf Quell- und Zieldateien über ein Array mit gleichem Index zu, hast du nun aber eine unterschiedliche Dateienanzahl, dann ist ja namenQ und namenZ nicht dasselbe.
BSP:
Quelle:
hallo.txt
welt.txt

Ziel (leer):

--> namenQ = {"...\hallo.txt", "...\welt.txt"} namenZ = {} // weil keine Dateien im Zielordner liegen

Konsequenz:
dirZ = new FileInfo(namenZ); führt zu nem schönen "ArrayIndexOutOfBounds"-Fehler


Schlimmer wirds dann nur noch, wenn du in beiden Ordnern Dateien hast.

Mein Vorschlag wäre folgender:
- rekursiver Ansatz für sync
- einfache foreach über quelldateien

Code:
private void SyncDir(DirectoryInfo diSrc, string dest)
{
    string destFile;
    Directory.CreateDirectory(dest);

    foreach (DirectoryInfo di in diSrc.GetDirectories())
    {
        SyncDir(di, dest + @"\" + di.Name); // rekursiver Aufruf für Verzeichnis
    }

    foreach (FileInfo fi in diSrc.GetFiles())
    {
        destFile = dest + @"\" + fi.Name;
        if (File.Exists(destFile))
        {
            if (File.GetLastWriteTime(destFile) >= fi.LastWriteTime)
                continue; // Datei in Zielverzeichnis ist neuer, nicht kopieren
        }
        else
        {
            fi.CopyTo(destFile, true); // Datei in Zielverzeichnis existiert nicht oder ist älter
        }
    }
}

//edit: sehe gerade du hast eh eine CopyDirectory-Funktion... Alles was du unter "btnCopy_Click" stehen hast bringt nichts. Ein simpler Aufruf von CopyDirectory(src,dst) synct dir dein Verzeichnis... Die Abfragen ob neuer oder älter machst du dann direkt wenn es darum geht eine Datei zu kopieren.

Und noch als Anmerkung. DirectoryInfo.FullName ist zuviel des Guten ;) Denn du willst ja keine Verzeichnisse aller "C:\Ziel\C:\Quelle\Ordner" sondern "C:\Ziel\Ordner" erstellen.
 
Zuletzt bearbeitet:
Vielen dank erstmal für deine Ratschläge. Sie haben mir viel weitergeholfen.

Ich würde erstmal gerne versuchen mit dem Ansatz den ich habe zu gucken wie weit ich damit komme.

Jetzt stehe ich eben vor dem was du mir Prophezeit hast und zwar ist das Array in dem die Zielpfade gespeichert sind "out of Range".

Ich habe nun das Array mit der Array.length länge von dem Quellen array initzialisiert. Jedoch wird mein Array einfach von der Methode: Directory.GetFileSystemEntries(txtZiel.Text); runtergekürzt.

z.B. hatte ich nach dem initzialisieren von namenZ[] drei freie plätze im Array und danach wird das Array einfach runtergekürzt wenn z.B. die Methode nur 2 pfade zurückliefert. Jedoch möchte ich das das dritte noch freibleibt.

Was kann ich da machen ?
 
Ist doch klar dass es gekürzt wird, damit es nicht gekürzt wird, müsstest du es folgendermaßen machen:
Code:
namenQ = Get...(quelle);
help = Get...(ziel);
if (help.Length < namenQ.Length)
   namenZ = new string[namenQ.Length];
else
   namenZ = new string[help.Lenght];

for (int i=0; i < help.Lenght; i++)
{
   namenZ[i] = help[i];
}

Aber der Ansatz ist einfach nur Falsch, da du über den Index nichtnotwenigerweise dieselben Dateinamen bekommst, und damit endest, dass du "Quelle\hallo.txt" mit "Ziel\tschüss.txt" vergleichst.

Besser ist eben der Ansatz, basierend auf den Quellnamen dir die Zielnamen zu generieren (wenn du es schon nicht on-the-fly machen willst):

Code:
namenZ = (from string fsObject in namenQ select dest + fsObject.Substring(fsObject.LastIndexOf(@"\"))).ToArray();

Wobei hier LINQ genutzt wird. Wenn du das nicht kannst kannst du das ganze auch als foreach or for-Schleife umschreiben:
Code:
for (int i = 0; i< namenQ.Length; i++)
{
    namenZ[i] = dest + namenQ[i].Substring(namenQ[i].LastIndexOf(@"\"));
}
 
Zuletzt bearbeitet:
Zurück
Oben