How do I get a directory size (files in the directory) in C#?

I want to be able to get the size of one of the local directories using C#. I’m trying to avoid the following (pseudo like code), although in the worst case scenario I will have to settle for this:

    int GetSize(Directory)
    {
        int Size = 0;

        foreach ( File in Directory )
        {
            FileInfo fInfo of File;
            Size += fInfo.Size;
        }

        foreach ( SubDirectory in Directory )
        {
            Size += GetSize(SubDirectory);
        }
        return Size;
    }

Basically, is there a Walk() available somewhere so that I can walk through the directory tree? Which would save the recursion of going through each sub-directory.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

A very succinct way to get a folder size in .net 4.0 is below. It still suffers from the limitation of having to traverse all files recursively, but it doesn’t load a potentially huge array of filenames, and it’s only two lines of code. Make sure to use the namespaces System.IO and System.Linq.

private static long GetDirectorySize(string folderPath)
{
    DirectoryInfo di = new DirectoryInfo(folderPath);
    return di.EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}

Method 2

If you use Directory.GetFiles you can do a recursive seach (using SearchOption.AllDirectories), but this is a bit flaky anyway (especially if you don’t have access to one of the sub-directories) – and might involve a huge single array coming back (warning klaxon…).

I’d be happy with the recursion approach unless I could show (via profiling) a bottleneck; and then I’d probably switch to (single-level) Directory.GetFiles, using a Queue<string> to emulate recursion.

Note that .NET 4.0 introduces some enumerator-based file/directory listing methods which save on the big arrays.

Method 3

Here my .NET 4.0 approach

public static long GetFileSizeSumFromDirectory(string searchDirectory)
{
 var files = Directory.EnumerateFiles(searchDirectory);

 // get the sizeof all files in the current directory
 var currentSize = (from file in files let fileInfo = new FileInfo(file) select fileInfo.Length).Sum();

 var directories = Directory.EnumerateDirectories(searchDirectory);

 // get the size of all files in all subdirectories
 var subDirSize = (from directory in directories select GetFileSizeSumFromDirectory(directory)).Sum();

 return currentSize + subDirSize;
}

Or even nicer:
// get IEnumerable from all files in the current dir and all sub dirs
var files = Directory.EnumerateFiles(searchDirectory,"*",SearchOption.AllDirectories);

// get the size of all files
long sum = (from file in files let fileInfo = new FileInfo(file) select fileInfo .Length).Sum();

As Gabriel pointed out this will fail if you have a restricted directory under the searchDirectory!

Method 4

You could hide your recursion behind an extension method (to avoid the issues Marc has highlighted with the GetFiles() method):

public static class UserExtension
{
  public static IEnumerable<FileInfo> Walk(this DirectoryInfo directory)
  {
    foreach(FileInfo file in directory.GetFiles())
    {
      yield return file;
    }

    foreach(DirectoryInfo subDirectory in directory.GetDirectories())
    { 
      foreach(FileInfo file in subDirectory.Walk())
      {
        yield return file;
      }
    }
  }
}

(You probably want to add some exception handling to this for protected folders etc.)

Then:

using static UserExtension;

long totalSize = 0L;
var startFolder = new DirectoryInfo("<path to folder>");

// iteration
foreach(FileInfo file in startFolder.Walk())
{
    totalSize += file.Length;
}

// linq
totalSize = di.Walk().Sum(s => s.Length);

Basically the same code, but maybe a little neater…

Method 5

First, forgive my poor english ;o)
I had a problem that took me to this page : enumerate files of a directory and his subdirectories without blocking on an UnauthorizedAccessException, and, like the new method of .Net 4 DirectoryInfo.Enumerate…, get the first result before the end of the entire query.

With the help of various examples found here and there on the web, I finally write this method :

public static IEnumerable<FileInfo> EnumerateFiles_Recursive(this DirectoryInfo directory, string searchPattern, SearchOption searchOption, Func<DirectoryInfo, Exception, bool> handleExceptionAccess)
{
    Queue<DirectoryInfo> subDirectories = new Queue<DirectoryInfo>();
    IEnumerable<FileSystemInfo> entries = null;

    // Try to get an enumerator on fileSystemInfos of directory
    try
    {
        entries = directory.EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
    }
    catch (Exception e)
    {
        // If there's a callback delegate and this delegate return true, we don't throw the exception
        if (handleExceptionAccess == null || !handleExceptionAccess(directory, e))
            throw;
        // If the exception wasn't throw, we make entries reference an empty collection
        entries = EmptyFileSystemInfos;
    }

    // Yield return file entries of the directory and enqueue the subdirectories
    foreach (FileSystemInfo entrie in entries)
    {
        if (entrie is FileInfo)
            yield return (FileInfo)entrie;
        else if (entrie is DirectoryInfo)
            subDirectories.Enqueue((DirectoryInfo)entrie);
    }

    // If recursive search, we make recursive call on the method to yield return entries of the subdirectories.
    if (searchOption == SearchOption.AllDirectories)
    {
        DirectoryInfo subDir = null;
        while (subDirectories.Count > 0)
        {
            subDir = subDirectories.Dequeue();
            foreach (FileInfo file in subDir.EnumerateFiles_Recursive(searchPattern, searchOption, handleExceptionAccess))
            {
                yield return file;
            }
        }
    }
    else
        subDirectories.Clear();
}

I use a Queue and a recursive method to keep traditional order (content of directory and then content of first subdirectory and his own subdirectories and then content of the second…). The parameter “handleExceptionAccess” is just a function call when an exception is thrown with a directory; the function must return true to indicate that the exception must be ignored.

With this methode, you can write :

DirectoryInfo dir = new DirectoryInfo("c:\temp");
long size = dir.EnumerateFiles_Recursive("*", SearchOption.AllDirectories, (d, ex) => true).Sum(f => f.Length);

And here we are : all exception when trying to enumerate a directory will be ignore !

Hope this help

Lionel

PS : for a reason I can’t explain, my method is more quick than the framework 4 one…

PPS : you can get my test solutions with source for those methods : here TestDirEnumerate. I write EnumerateFiles_Recursive, EnumerateFiles_NonRecursive (use a queue to avoid recursion) and EnumerateFiles_NonRecursive_TraditionalOrder (use a stack of queue to avoid recursion and keep traditional order). Keep those 3 methods has no interest, I write them only for test the best one. I think to keep only the last one.
I also wrote the equivalent for EnumerateFileSystemInfos and EnumerateDirectories.

Method 6

Have a look at this post:

http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/eed54ebe-facd-4305-b64b-9dbdc65df04e

Basically there is no clean .NET way, but there is a quite straightforward COM approach so if you’re happy with using COM interop and being tied to Windows, this could work for you.

Method 7

the solution is already here https://stackoverflow.com/a/12665904/1498669

as in the duplicate How do I Get Folder Size in C#? shown -> you can do this also in c#

first, add the COM reference “Microsoft Scripting Runtime” to your project and use:

var fso = new Scripting.FileSystemObject();
var folder = fso.GetFolder(@"C:Windows");
double sizeInBytes = folder.Size;
// cleanup COM
System.Runtime.InteropServices.Marshal.ReleaseComObject(folder);
System.Runtime.InteropServices.Marshal.ReleaseComObject(fso);

remember to cleanup the COM references

Method 8

I’ve been looking some time ago for a function like the one you ask for and from what I’ve found on the Internet and in MSDN forums, there is no such function.

The recursive way is the only I found to obtain the size of a Folder considering all the files and subfolders that contains.

Method 9

You should make it easy on yourself. Make a method and passthrough the location of the directory.

    private static long GetDirectorySize(string location) {
        return new DirectoryInfo(location).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
    }

-G


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x