【问题标题】:How do I get a directory size (files in the directory) in C#?如何在 C# 中获取目录大小(目录中的文件)?
【发布时间】:2010-11-10 06:05:05
【问题描述】:

我希望能够使用 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() 以便我可以遍历目录树?这将节省遍历每个子目录的递归。

【问题讨论】:

    标签: c# asp.net winforms .net


    【解决方案1】:

    在 .net 4.0 中获取文件夹大小的一种非常简洁的方法如下。它仍然受到必须递归遍历所有文件的限制,但它不会加载潜在的巨大文件名数组,而且它只有两行代码。确保使用命名空间System.IOSystem.Linq

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

    【讨论】:

    • 我建议您使用 * 而不是 * 。 * 因为文件名不需要 .
    • 我遵循 Joe 的推理,但我认为没有必要,因为 Windows 操作系统会匹配 * 。 * 针对文件/文件夹名称的模式,无论它们是否包含“。”或不。我认为这没有什么区别,但我很想知道我是否错了。当然,如果是 Mono 在不同的操作系统上运行,那么它可能会有所不同。
    • 非常好。除非您想在每个目录的基础上处理 UnauthorizedAccessException、PathTooLongException 等。
    • 如果在 Visual Basic 中编码:di.EnumerateFiles(".", IO.SearchOption.AllDirectories).Sum(Function(fi) fi.Length)
    【解决方案2】:

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

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

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

    然后:

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

    基本相同的代码,但可能更简洁一些...

    【讨论】:

      【解决方案3】:

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

      如重复的How do I Get Folder Size in C#? 所示 -> 您也可以在 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 引用

      【讨论】:

      • 如何在linux中与mono一起使用?
      【解决方案4】:

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

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

      -G

      【讨论】:

      • 一如既往,使用文件掩码“*”而不是“*.*”,因为并非所有文件都有扩展名...
      【解决方案5】:

      首先,请原谅我糟糕的英语;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();
      }
      

      我使用队列和递归方法来保持传统顺序(目录内容,然后是第一个子目录的内容和他自己的子目录,然后是第二个子目录的内容......)。参数“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(使用队列堆栈来避免递归并保持传统顺序)。保留这三种方法没有任何意义,我写它们只是为了测试最好的一种。我想只保留最后一个。 我还为 EnumerateFileSystemInfos 和 EnumerateDirectories 编写了等效项。

      【讨论】:

      • 我在这个版本中犯了一个错误,因为我使用 searchPattern 搜索子目录。因此,如果子目录与 searchPattern 不匹配,我不会探索它...[br] 我编写了新版本来纠正这个问题:但是,我必须对目录执行两个请求:一个带有 searchPattern,另一个没有 searchPattern = => 性能不如以前。
      • 所以我添加了一个没有搜索模式的版本,它更快。在这里查看我的测试解决方案:link
      • 也许我遗漏了一些东西,但是使用这种方法你仍然会得到不完整的列表,对吧?如果我被授权查看文件夹 A 和 C 而不是 B,并且 Enumerate 检查 A,然后是 B,然后是 C,它将在 B 处停止,并且无法计算 C。
      【解决方案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 下有一个受限目录,这将失败!

      【讨论】:

      • 最后一行代码的小错字,应该是: // 获取所有文件的大小 long sum = (from file in files let fileInfo = new FileInfo(file) select fileInfo.Length).Sum ();
      • 而且如果你在searchDirectory下有一个受限目录,它就会失败!要在框架的未来版本中看到该解决方案:connect.microsoft.com/VisualStudio/feedback/details/512171/…
      • 感谢您的 cmets Gabriel。我已修正错字并包含可能的失败警告。
      【解决方案7】:

      看看这篇文章:

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

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

      【讨论】:

        【解决方案8】:

        如果您使用Directory.GetFiles,您可以进行递归搜索(使用SearchOption.AllDirectories),但这有点不稳定(特别是如果您无权访问其中一个子目录) - 并且可能涉及一个巨大的单个数组回来了(警告喇叭...)。

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

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

        【讨论】:

          【解决方案9】:

          我前段时间一直在寻找类似您要求的功能,从我在 Internet 和 MSDN 论坛上找到的内容来看,没有这样的功能。

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

          【讨论】:

            猜你喜欢
            • 2010-10-03
            • 2011-07-18
            • 1970-01-01
            • 2010-10-03
            • 1970-01-01
            • 1970-01-01
            • 2020-08-02
            • 1970-01-01
            • 2012-03-08
            相关资源
            最近更新 更多