3

Now here is the problem: I have a lot of code that all does the same thing. That is, it copies the contents of two folders into a destination folder and merges them in the destination folder. My problem is, I cannot find out (after much Googling) how to actually copy the source directories + contents as opposed to just its contents and sub folders which then end up merged.

It may be how I'm obtaining the directories: I use a Folder Selection Dialog, add the path name to a listbox (To display) and then create a list of (string) directories from the items in the listbox.

Here is the code so far. (Some is from MSDN)

public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
    {
        if (source.FullName.ToLower() == target.FullName.ToLower())
        {
            return;
        }

        // Check if the target directory exists, if not, create it. 
        if (Directory.Exists(target.FullName) == false)
        {
            Directory.CreateDirectory(target.FullName);
        }

        // Copy each file into it's new directory. 
        foreach (FileInfo fi in source.GetFiles())
        {
            fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
        }

        // Copy each subdirectory using recursion. 
        foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
        {
            DirectoryInfo nextTargetSubDir =
                target.CreateSubdirectory(diSourceSubDir.Name);
            CopyAll(diSourceSubDir, nextTargetSubDir);
        }
    }
    //This is inside a button click Method

    List<string> pathList = new List<string>();
        pathList = lstBox.Items.Cast<String>().ToList();

        string sourceDirectory;
        string targetDirectory;

        DirectoryInfo dirSource;
        DirectoryInfo dirTarget;

        for (int i = 0 ; i < pathList.Count; i++)
        {
            sourceDirectory = pathList.ElementAt(i);
            targetDirectory = browserSave.SelectedPath; //browserSave is the Folder Selection Dialog
            dirSource = new DirectoryInfo(sourceDirectory);
            dirTarget = new DirectoryInfo(targetDirectory);

            CopyAll(dirSource, dirTarget);                
        }

Annoyingly C# has no Directory.Copy function which would be extremely useful. Recap.

I Select Folder 1. I select Folder 2. I Select Destination Folder. I Press OK. Expected Result: Destination Folder has two folders, Folder 1 and Folder 2 inside. Both has all files inside. Actual Result: Destination Folder has loose files merged, and sub directories of source folders intact. (Which is whats annoying)

I hope this is enough info for you professionals to help with.

Millie Smith
  • 4,536
  • 2
  • 24
  • 60
Sizza
  • 105
  • 2
  • 11
  • 2
    A much cleaner approach would be if your function took two String objects (source and destination paths) as a parameter. Check accepted answer here: http://stackoverflow.com/questions/1066674/how-do-i-copy-a-folder-and-all-subfolders-and-files-in-net/1066707#1066707 – tpolyak Oct 20 '13 at 16:50
  • I've done more searching, and even added the reference to the Visual Basic DLL - which has its own CopyDirectory() Method. It does the exact same problem. The problem must lie with how I'm getting the source directory or something. Not sure... Thanks! – Sizza Oct 20 '13 at 17:11
  • 1
    @Sizza - yes it is how you are calling the copy -- see my answer. – Hogan Oct 20 '13 at 17:21

4 Answers4

1

The problem is you are never making a new target for your destination -- this will make a new target with the same name as the source for each iteration of the loop and then copy to that target.

for (int i = 0 ; i < pathList.Count; i++)
{
   sourceDirectory = pathList.ElementAt(i);
   targetDirectory = browserSave.SelectedPath; //browserSave is the Folder Selection Dialog
   dirSource = new DirectoryInfo(sourceDirectory);

   string targetPath = target.Fullname+
                  Path.DirectorySeparatorChar+
                  sourceDirectory.Split(Path.DirectorySeparatorChar).Last());

   Directory.CreateDirectory(targetPath);

   dirTarget = new DirectoryInfo(targetPath);

   CopyAll(dirSource, dirTarget);                
 }

caveat I did not test so I might have typos, but you get the idea.

Hogan
  • 69,564
  • 10
  • 76
  • 117
  • Aha, this is what I thought. I figured this might be the problem after posting. Thank you, I shall test it now. – Sizza Oct 20 '13 at 17:26
  • Right so I tested this in the Button Method. It does nothing whatsoever. (Which is progress in a way). Maybe I need to create the new target, in the copy method itself? – Sizza Oct 20 '13 at 17:36
  • 1
    @Sizza - this does create the target... Right where it says create directory -- run in debugger and see what the variables are. Maybe browserSave.SelectedPath was not set? – Hogan Oct 20 '13 at 17:37
  • EDIT Nevermind i accidently changed FullName to Name. IT WORKS <3 Thank you so much – Sizza Oct 20 '13 at 17:41
0

Instead of DirectoryInfo pass string as a parameter. See the code below.

private void DirectoryCopy(
    string sourceDirName, string destDirName, bool copySubDirs)
{
  DirectoryInfo dir = new DirectoryInfo(sourceDirName);
  DirectoryInfo[] dirs = dir.GetDirectories();

  // If the source directory does not exist, throw an exception.
    if (!dir.Exists)
    {
        throw new DirectoryNotFoundException(
            "Source directory does not exist or could not be found: "
            + sourceDirName);
    }

    // If the destination directory does not exist, create it.
    if (!Directory.Exists(destDirName))
    {
        Directory.CreateDirectory(destDirName);
    }


    // Get the file contents of the directory to copy.
    FileInfo[] files = dir.GetFiles();

    foreach (FileInfo file in files)
    {
        // Create the path to the new copy of the file.
        string temppath = Path.Combine(destDirName, file.Name);

        // Copy the file.
        file.CopyTo(temppath, false);
    }

    // If copySubDirs is true, copy the subdirectories.
    if (copySubDirs)
    {

        foreach (DirectoryInfo subdir in dirs)
        {
            // Create the subdirectory.
            string temppath = Path.Combine(destDirName, subdir.Name);

            // Copy the subdirectories.
            DirectoryCopy(subdir.FullName, temppath, copySubDirs);
        }
    }
}

In main function.

static void Main(string[] args)
    {

        List<string> directoryNames = new List<string>()  // For multiple source folders
        {
            "C:\\Folder1", "C:\\Folder2"
        };

        string destDirName = "C:\\Folder3";
        foreach (string sourceDirName in directoryNames)
        {
            DirectoryCopy(sourceDirName, destDirName, true)
        }
    }
Muhammad Umar
  • 3,761
  • 1
  • 24
  • 36
  • I have use this code. It will copy all source directory, sub directories and files into destination folder. Where actually the problem is ? – Muhammad Umar Oct 20 '13 at 17:07
  • I understand the code works, what I need it to do is copy the source folder + contents into a new folder which I select. What this code does, as I've just tried it, is copy just the contents of the source folder into a destination folder. Problem here is when I select more than one folder to copy, it merges them, where I want to keep the tree structure. – Sizza Oct 20 '13 at 17:19
  • You want to copy more then one folders means you source folders are more then one. Is am right ?? – Muhammad Umar Oct 20 '13 at 17:26
  • I have updated my question for more then one source directories – Muhammad Umar Oct 20 '13 at 17:43
  • Thank you, Hogan has solved it. I appreciate your work, and agree strings might be cleaner. – Sizza Oct 20 '13 at 17:51
0

Try the following. You'll obviously need to set the source and destination folders accordingly when you invoke action. Also I would suggest that you do not embed any logic in event handlers. Hope this helps.

            Action<string, string> action = null;
            action = (source,dest) =>
                {
                    if(Directory.Exists(source))
                    {
                        DirectoryInfo sInfo = new DirectoryInfo(source);
                        if (!Directory.Exists(dest))
                        {
                            Directory.CreateDirectory(dest);
                        }
                        Array.ForEach(sInfo.GetFiles("*"), a => File.Copy(a.FullName, Path.Combine(dest,a.Name)));
                        foreach (string dir in Directory.EnumerateDirectories(source))
                        {
                            string sSubDirPath = dir.Substring(source.Length+1,dir.Length-source.Length-1);
                            string dSubDirPath = Path.Combine(dest,sSubDirPath);
                            action(dir, dSubDirPath);
                        }
                    }
                };
            action(@"C:\source", @"C:\dest");
Abhijeet Patel
  • 6,562
  • 8
  • 50
  • 93
-1

This will help you to solve your problem.This function is a generic recursive function for copy folder with or not sub folders with merging.

public static void DirectoryCopy(string sourceDirPath, string destDirName, bool isCopySubDirs)
{
    // Get the subdirectories for the specified directory.
    DirectoryInfo directoryInfo = new DirectoryInfo(sourceDirPath);
    DirectoryInfo[] directories = directoryInfo.GetDirectories();
    if (!directoryInfo.Exists)
    {
        throw new DirectoryNotFoundException("Source directory does not exist or could not be found: "
            + sourceDirPath);
    }
    DirectoryInfo parentDirectory = Directory.GetParent(directoryInfo.FullName);
    destDirName = System.IO.Path.Combine(parentDirectory.FullName, destDirName);

    // If the destination directory doesn't exist, create it. 
    if (!Directory.Exists(destDirName))
    {
        Directory.CreateDirectory(destDirName);
    }
    // Get the files in the directory and copy them to the new location.
    FileInfo[] files = directoryInfo.GetFiles();

    foreach (FileInfo file in files)
    {
        string tempPath = System.IO.Path.Combine(destDirName, file.Name);

        if (File.Exists(tempPath))
        {
            File.Delete(tempPath);
        }

        file.CopyTo(tempPath, false);
    }
    // If copying subdirectories, copy them and their contents to new location using recursive  function. 
    if (isCopySubDirs)
    {
        foreach (DirectoryInfo item in directories)
        {
            string tempPath = System.IO.Path.Combine(destDirName, item.Name);
            DirectoryCopy(item.FullName, tempPath, isCopySubDirs);
        }
    }
}
Thilina H
  • 5,754
  • 6
  • 26
  • 56