user10191234
user10191234

Reputation: 637

Walk and create directory tree level by level

I was tasked creating a small(?) utility that walks a directory tree level by level and creating each level by calling a CreateDir(folder, parent) function that I have no access to its source code and creates a directory if it finds its parent. My question is similar to this question. Assuming I have this structure

A
-B
--D
---G
--E
-C
--F

I should create A first, then B and C, then D,E, and F and then G. Of course there is no limit to the depth.

I have created this method.

(IEnumerable<string>, IEnumerable<string>) GetAllFolders(string root)
{
 var folders = Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories).Select(path => path.Replace(root, "").Substring(1));
 var parents = folders.Select(path => path.Substring(0, (path.LastIndexOf(@"\") + 1) == 0 ? (path.LastIndexOf(@"\") + 1) : (path.LastIndexOf(@"\") ) ));

 var listOfFolders = folders.ToList();
 var listOfParents = parents.ToList();
 return (listOfFolders, listOfParents);
}

And I try to create the structure using

foreach (var tuple in folders.Zip(parents, (x, y) => (x, y)))
      {
      if (tuple.y == String.Empty)
             CreateDir(tuple.x,destination);
      else
             CreateDir(tuple.x, tuple.y);
      }        

where destination is a hardcoded path for the destination folder, folders and parents are the results of GetAllFolders.

I believe that I am overthinking it and that's why it is not working. Any simpler ideas?

Upvotes: 1

Views: 411

Answers (1)

IV.
IV.

Reputation: 9511

Is this actually simpler? Not sure. Does it work? Yes. You could try a Linq.GroupBy query that ensures the list of source directories are sorted by depth and then combine this expression with a string.Replace that removes the source folder path, leaving only short names of all the directories it contains. By calling in order of depth, the parent is guaranteed to exist when the child folder is added.

This test routine uses a mock (shown at bottom) of the inaccessible CreateDirectory method you mention in your post.

static void Main(string[] args)
{
    // The Copy-From source is mocked in the output directory.
    var source = AppDomain.CurrentDomain.BaseDirectory;

    // The Copy-To destination is mocked in local app data for this app
    var destination = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
        "create_directories_by_depth"
    );

    // Making sure the list of directories is sorted by depth
    var directoryLevels = 
        Directory
        .GetDirectories(source, String.Empty, SearchOption.AllDirectories)
        .Select(path=>path.Replace(source, String.Empty))
        .GroupBy(path=>path.Split(Path.DirectorySeparatorChar).Length)
        .OrderBy(group=>group.Key);

    // Ensure that the top-level folder exists.
    Directory.CreateDirectory(destination);

    foreach (
        var directoryLevel 
        in directoryLevels)
    {
        var shortPaths = directoryLevel.ToArray();
        foreach (
            var folder 
            in shortPaths.Select(shortPath=>Path.Combine(destination, shortPath)))
        {
            var parse = folder.Split(Path.DirectorySeparatorChar).ToList();
            parse.Remove(parse.Last());
            var parent = Path.Combine(parse.ToArray());
            // MAKE THE CALL
            CreateDirectory(folder, parent);
        }
    }
    foreach (var directory in Directory.GetDirectories(destination, String.Empty, SearchOption.AllDirectories))
    {
        Console.WriteLine(directory);
    }
    Process.Start("explorer.exe", destination);
}

The inaccessible method:

// No access to source code
// Creates a directory if it finds its parent
private static void CreateDirectory(string folder, string parent)
{
    if (Directory.Exists(parent))
    {
        Directory.CreateDirectory(folder);
    }
    else Debug.Assert(false, "Expecting to find existing parent!");
}

Here is the copied directory structure:

copied directory structure

Upvotes: 1

Related Questions