Get Directory Structure using Linq?

I have an app where I get a list of drives on the computer and when you select one I populate a tree control with the directories and files.

I was thinking of trying this using linq to loop round each directory and get its child directories.

Has anyone done anything like this before?



You can use LINQ no problem, although it's a simple enough task that the file system-related code is likely to be longer than the LINQ-related code:

    private static TreeNode AddDirectory(DirectoryInfo directory)
    DirectoryInfo[] subdirs = directory.GetDirectories();
    FileInfo[] files = directory.GetFiles();
    IEnumerable<TreeNode> subdirNodes = from subdir in subdirs select AddDirectory(subdir);
    IEnumerable<TreeNode> fileNodes = from file in files select new TreeNode(file.Name);
    return new TreeNode(

Here's an example of how to do just that: Using-LINQ-to-access-the-file-system

Here's another one: How-to-search-the-file-system-using-linq-queries

As an aside - you may be interested to know that .NET 4.0 is getting LINQ-enable file operations built in (proper lazy ones, apparently - not juts iterating over an array). Look for "File System Enumeration Improvements" on this BCL Team Blog entry.

Usually when a UI displays a tree of files and folders, it doesn't scan the whole hierarchy in a single shot. Instead it gathers just enough information for the nodes that are expanded. Then when the user expands a node, it then goes to the effort of finding out what needs to be placed under that node.

The reason is simply because the number of files and directories on many people's system drives can get very large, and so your application will freeze up for a little while if they ask to see the root of drive C:.

It's slightly different depending on whether you're using WPF or Windows Forms. In WPF, the Expanded event is on the TreeViewItem itself, whereas in Windows Forms there are several expansion events on the TreeView (and no events on TreeNode). But the pattern is much the same.

When you add a tree node that represents a folder, create a dummy node under it. Give it some special identification (a special flag in the Tag property, or perhaps a unique name that contains non-valid filesystem characters). This will allow the user to expand that node. Then in your expansion-event handler, look at the first child node - if it is the special dummy node, remove it and then create the real set of child nodes for that node. This will ensure that you only gather the real nodes one time per directory.

Here's a rough idea for WPF:

TreeViewItem folderNode = new TreeViewItem { Header = Path.GetFileName(folderPath) };

// create the dummy item under it
TreeViewItem dummy = new TreeViewItem { Tag = _dummyTag };

folderNode.Expanded += delegate
        if (folderNode.Items.Count == 1)
            if (((TreeViewItem)folderNode.Items[0]).Tag == _dummyTag)
                CreateFolderChildren(folderNode, folderPath);

The _dummyTag can just be a field:

private static readonly object _dummyTag = new object();

Let me pimp my tree extensions again :)


var di = new DirectoryInfo("foo");
var q = di.TraverseDepthFirst( x => x.GetFiles(), x => x.GetDirectories());
var nq = from fs in q
         from f in fs
         select f;

foreach (FileInfo dirfiles in nq)

If you use GetFiles, you'll start a blocking operation that will return an array. If you instead use EnumerateFiles you get lazy evaluation, allowing you to start working before all of the files have been returned from the file system. Much more LINQy.


var files = directory.EnumerateFiles();
foreach (var file in files)
    // do stuff

Need Your Help

Difference between std::tr1::array and boost::array

c++ boost arrays std tr1

I was under the impression that std::tr1::array was the same as the boost::array in that it would throw an exception when accessing an index out of bounds. In fact, I took a peek in the header and...

Can't assign roles from azure AD app manifest

azure active-directory manifest roles

I was trying to implement role based authorization in my azure application as described in the