(Print this page)

Getting folder size
Published date: Sunday, January 15, 2017
On: Moer and Éric Moreau's web site

I saw an interesting question on Experts Exchange last week. The guy wanted to loop through all the folders (including subfolders) to discover how many files are stored in them and how big are the files.

It is not a complex one but it requires a bit of recursion to loop through the folders, a bit of error handling because there are folders that might be protected.

So here comes the first article of January!

Downloadable code

This month solution contains both VB and C# projects. The solution was created using Visual Studio 2017 RC but the code should work starting with the .Net Framework 4.0 (Visual Studio 2010).

Figure 1: The demo application in action



Very simple interface

Only 3 controls are required to build this demo application. A button to launch the process. A label to show some progression. A datagrid to show the result.

Storing the results in memory

Before showing the results in the datagrid, we need a way to store the values. I wanted something simple. What is easiest than a structure? And to hold the full list of, a simple generic List of that structure and we will be in business.

Structure FolderStruct
    Public Property Path As String
    Public Property NumberOfFiles As Integer
    Public Property FileSize As Long
End Structure

Private _folders As List(Of FolderStruct)
struct FolderStruct
{
    public String Path { get; set; }
    public int NumberOfFiles { get; set; }
    public long FileSize { get; set; }
}

private List<FolderStruct> _folders;

Notice that if you are not using auto-properties in C#, you might not see the results in the datagrid.

Launching the process

The process of looping through the folders will be triggered by clicking the button. The code behind this button is only 4 lines of code:

  • Initialize and empty list of the structure
  • Call the recursive method
  • Show the results in the grid
  • Show that the process is completed in the label
_folders = New List(Of FolderStruct)
LoadFolderSize("C:\", 0)
dataGridView1.DataSource = _folders.ToList()
label1.Text = "Process completed"
_folders = new List<FolderStruct>();
LoadFolderSize("C:\\", 0);
dataGridView1.DataSource = _folders.ToList();
label1.Text = @"Process completed";

The recursive method

So this LoadFolderSize method will be called recursively to loop through all the folders and subfolders of a starting point (c:\ in my case).

Because the process can be quite long, the first line of this method is to show the folder being processed in the label. This method will be called in a tight loop. If we want to see the label being refreshed, we need to call the DoEvents method.

The next block of lines creates a DirectoryInfo instance with the current folder. The path, the number of files, and the total size (in bytes) is added to the list of folder.

Once we have the data for the current folder, we can loop through the list of directories and for each one of them, recall the very same method we are in passing in arguments the path of this sub-directory. If we cannot get access, an exception is raised and an entry with -1 in the NumberOfFiles and FileSize is added to the list.

Private Sub LoadFolderSize(pFolder As String, pLevel As Integer)
    label1.Text = pFolder
    Application.DoEvents()

    Dim dInfo As DirectoryInfo = New DirectoryInfo(pFolder)
    _folders.Add(New FolderStruct() With {
            .Path = New String("-"c, pLevel) + pFolder,
            .NumberOfFiles = dInfo.EnumerateFiles().Count(),
            .FileSize = dInfo.EnumerateFiles().Sum(Function(file) file.Length)
        })

    For Each subDir As String In Directory.GetDirectories(pFolder)
        Try
            LoadFolderSize(subDir, pLevel + 1)
        Catch
            _folders.Add(New FolderStruct() With {
                .Path = New String("-"c, pLevel) + subDir,
                .NumberOfFiles = -1,
                .FileSize = -1
                })
        End Try
    Next
End Sub
private void LoadFolderSize(string pFolder, int pLevel)
{
    label1.Text = pFolder;
    Application.DoEvents();

    DirectoryInfo dInfo = new DirectoryInfo(pFolder);

    _folders.Add(new FolderStruct
    {
        Path = new string('-', pLevel) + pFolder,
        NumberOfFiles = dInfo.EnumerateFiles().Count(),
        FileSize = dInfo.EnumerateFiles().Sum(file => file.Length)
    });

    foreach (string subDir in Directory.GetDirectories(pFolder))
    {
        try
        {
            LoadFolderSize(subDir, pLevel + 1);
        }
        catch
        {
            _folders.Add(new FolderStruct
            {
                Path = new string('-', pLevel) + subDir,
                NumberOfFiles = -1,
                FileSize = -1
            });
        }
    }
}

Getting this further

With this little example, you have the base of an application you can get a lot further. One example would be to store the results in a file or database to be able to compare against another execution (say you run it on a weekly basis). You would then be able to easily detect which folder got the biggest increase (or decrease) during that period.

I will surely expand this sample further to monitor network folders if I get a couple of free hours (that will surely not happen in the next few months!).

Conclusion

Sometime, a sample question on forums requires a bit of thinking and simple code to put in place.


(Print this page)