如何在C#中获取目录大小(目录中的文件)?

时间:2009-07-13 09:53:02

标签: c# asp.net winforms .net

我希望能够使用C#获取其中一个本地目录的大小。我试图避免以下(伪代码),尽管在最坏的情况下我将不得不满足于此:

    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;
    }

基本上,是否有可以在某处使用Walk()以便我可以浏览目录树?这将保存遍历每个子目录的递归。

9 个答案:

答案 0 :(得分:32)

在.net 4.0中获取文件夹大小的一种非常简洁的方法如下。它仍然受到必须以递归方式遍历所有文件的限制,但它不会加载潜在的大量文件名,而且只有两行代码。

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

答案 1 :(得分:19)

如果您使用Directory.GetFiles,您可以执行递归搜索(使用SearchOption.AllDirectories),但无论如何这都有点不稳定(特别是如果您无法访问其中一个子目录) - 并且可能涉及一个巨大的单个阵列回来(警告klaxon ......)。

我会对递归方法感到满意,除非我能显示(通过分析)瓶颈;然后我可能会切换到(单级)Directory.GetFiles,使用Queue<string>来模拟递归。

请注意,.NET 4.0引入了一些基于枚举器的文件/目录列表方法,可以节省大数组。

答案 2 :(得分:6)

这是我的.NET 4.0方法

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;
}

甚至更好:

// 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();

正如Gabriel指出,如果您在searchDirectory下有一个受限制的目录,那么这将失败!

答案 3 :(得分:4)

您可以隐藏扩展方法后面的递归(以避免Marc使用GetFiles()方法突出显示的问题):

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;
        }
    }
}

(您可能希望为受保护的文件夹等添加一些异常处理。)

然后:

int totalSize = 0;

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

基本上是相同的代码,但也许有点整洁......

答案 4 :(得分:3)

首先,请原谅我可怜的英语; o) 我有一个问题带我到这个页面:枚举目录及其子目录的文件而不会阻止UnauthorizedAccessException,并且像.Net 4 DirectoryInfo.Enumerate ...的新方法一样,在结束之前得到第一个结果整个查询。

借助在网上找到的各种例子的帮助,我终于写了这个方法:

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();
}

我使用Queue和递归方法来保持传统的顺序(目录的内容,然后是第一个子目录的内容和他自己的子目录,然后是第二个的内容......)。参数“handleExceptionAccess”只是在用目录抛出异常时的函数调用;该函数必须返回true以指示必须忽略该异常。

使用这种方法,你可以写:

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

我们在这里:尝试枚举目录时的所有异常都将被忽略!

希望这个帮助

梅西

PS:因为我无法解释的原因,我的方法比框架4更快......

PPS:您可以使用这些方法的源代码获取我的测试解决方案:此处TestDirEnumerate。我编写EnumerateFiles_Recursive,EnumerateFiles_NonRecursive(使用队列来避免递归)和EnumerateFiles_NonRecursive_TraditionalOrder(使用一堆队列来避免递归并保持传统顺序)。保持这3种方法没有兴趣,我写它们只是为了测试最好的方法。我想只保留最后一个。 我还为EnumerateFileSystemInfos和EnumerateDirectories编写了等效文件。

答案 5 :(得分:1)

看一下这篇文章:

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

基本上没有干净的.NET方法,但有一种非常简单的COM方法,所以如果你对使用COM互操作并与Windows绑定感到满意,这可能对你有用。

答案 6 :(得分:1)

解决方案已经在https://stackoverflow.com/a/12665904/1498669

与所示的重复How do I Get Folder Size in C#?一样 - &gt;你也可以在c#

中做到这一点

首先,将COM引用“Microsoft Scripting Runtime”添加到项目中并使用:

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);

记得清理COM引用

答案 7 :(得分:0)

前段时间我一直在寻找类似于你所要求的功能,以及我在互联网和MSDN论坛上发现的功能,没有这样的功能。

考虑到包含所有文件和子文件夹,我发现获取文件夹大小的唯一递归方式。

答案 8 :(得分:-2)

你应该让自己轻松自如。制作方法并传递目录的位置。

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

-G