views:

1664

answers:

6

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.

A: 

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.

Doliveras
+9  A: 

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.

Marc Gravell
Thanks for that :)
ThePower
+3  A: 

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

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:

int totalSize = 0;

foreach(FileInfo file in directory.Walk())
{
    totalSize += file.Length;
}

Basically the same code, but maybe a little neater...

Martin Harris
+1  A: 

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.

DrJokepu
A: 

Not other good solution without using GetFiles())?

I need high performance, using many-many-many JPG files in folders...

What is the MAXIMUM number of files in a folder for high performance?

An idea - Use sum get files at start up, and then maintain that sum when adding files (or, if files are being added externally, use a polling task that checks new files by date).
Hertzel Guinness
+5  A: 

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!

Flo
Small typo on the last code line, should be: // get the size of all files long sum = (from file in files let fileInfo = new FileInfo(file) select fileInfo.Length).Sum();
Gabriel Mongeon
And if you have a restricted directory under the searchDirectory, it will fail! To see that resolve in a future version of the framework: https://connect.microsoft.com/VisualStudio/feedback/details/512171/directory-enumeratedirectory-etc-unusable-due-to-frequent-unauthorizedaccessexceptions-even-runas-administrator
Gabriel Mongeon
Thanks for your comments Gabriel. I have fixed the typo and included the possible fail warning.
Flo