Search code examples
c#directorycopysystem

C# Directory copying returns no error, but does not copy directory


I'm writing a very small app to copy a directory from one place to the other with some added automation. The entire application works flawlessly with exception of the actual copy method. The worst part is I'm getting no errors at all, and as most of you know, that's quite worse than getting errors.

Here is the method in question:

public static bool CopyDir(string sPath, string dPath)
        {
            string[] files = Directory.GetFiles(sPath);
            try
            {
                foreach (string file in files)
                {
                    string name = Path.GetFileName(file);

                    foreach (string dirPath in Directory.GetDirectories(sPath, "*",
                        SearchOption.AllDirectories))
                        Directory.CreateDirectory(dirPath.Replace(sPath, dPath));

                    foreach (string newPath in Directory.GetFiles(sPath, "*.*",
                        SearchOption.AllDirectories))
                        File.Copy(newPath, newPath.Replace(sPath, dPath), true);
                }
            } catch // this is no use because the Exception is empty.
            {
                return false;
            }
            return false; //the app keeps executing to here and I don't know why
        }

Variable dump from debugger:

  • sPath: "C:\\Users\\Jacob Jewett\\Downloads\\func1"
  • dPath: "C:\\Users\\Jacob Jewett\\AppData\\Roaming\\.minecraft\\saves\\data\\functions\\"
  • files: [0] "C:\\Users\\Jacob Jewett\\Downloads\\func1\\main.mcfunction"

Folder tree of Downloads\func1 (sPath):

func1
  main.mcfunction

EDIT (2:33PM): OK so here's my refactored code, it returns File in use error but does not copy anything.

   public static bool CopyDir(string sPath, string dPath)
        {
            try
            {
                foreach (string dirPath in Directory.GetDirectories(sPath, "*",
                    SearchOption.AllDirectories))
                    Directory.CreateDirectory(dirPath.Replace(sPath, dPath));

                foreach (string newPath in Directory.GetFiles(dPath, "*.*",
                    SearchOption.AllDirectories))
                    File.Copy(newPath, newPath.Replace(sPath, dPath), true);
                return true;
            }
            catch (UnauthorizedAccessException e)
            {
                MessageBox.Show("Attempt to copy failed. Raw: "+e,"IO Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

EDIT (8-29-17 12:09PM): I've done some tweaking to the method and I'm at a point where I now get a Access to path [path] is Denied., which is better than nothing but I haven't come across a working solution yet. I did some browsing on here for the error and most say to put File.SetAttributes() before the File.Copy() method is called. This has no effect. Alternatively, I tried setting the attribute Read-Only directory of the sPath1 to none before any copying is done, and this also has no effect.

Current code:

public static bool CopyDir(string sPath, string dPath)
{
    try
    {
        DirectoryInfo spdi = new DirectoryInfo(sPath);
        spdi.Attributes &= ~FileAttributes.ReadOnly;
        foreach (string dirPath in Directory.GetDirectories(sPath, "*",
            SearchOption.AllDirectories))
            Directory.CreateDirectory(dirPath);

        foreach (string newPath in Directory.GetFiles(dPath, "*.*",
            SearchOption.AllDirectories))
        { 
            File.SetAttributes(dPath, FileAttributes.Normal);
            File.Copy(sPath, newPath);
        }
        Directory.CreateDirectory(dPath);
        return true;
    }
    catch (UnauthorizedAccessException e)
    {
        MessageBox.Show("Attempt to copy failed. (UAC) Raw: "+e,"IO Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
        return false;
    }
}

Solution

  • Edit: I reread your code and I think I've got the real issue.

    The instructions below are quite sufficient to copy all subdirectories and files to the destination.

    foreach (string dirPath in Directory.GetDirectories(sPath, "*",
             SearchOption.AllDirectories))
             Directory.CreateDirectory(dirPath.Replace(sPath, dPath));
    
    foreach (string newPath in Directory.GetFiles(sPath, "*.*",
            SearchOption.AllDirectories))
            File.Copy(newPath, newPath.Replace(sPath, dPath), true);
    

    The outer foreach is redundant.

    Here is corrected code:

    public static bool CopyDir(string sPath, string dPath)
    {
        try
        {
             foreach (string dirPath in Directory.GetDirectories(sPath, "*",
                    SearchOption.AllDirectories))
                    Directory.CreateDirectory(dirPath.Replace(sPath, dPath));
    
             foreach (string newPath in Directory.GetFiles(sPath, "*.*",
                    SearchOption.AllDirectories))
                    File.Copy(newPath, newPath.Replace(sPath, dPath), true);
        }
        catch // this is no use because the Exception is empty.
        {
            return false;
        }
    
        return false; //the app keeps executing to here and I don't know why
    }
    

    That said, it is a good practice to do something with the Exception in the catch block. Even if it's just logging it :) That way you can rule it out if it's not logging.