计算Windows文件夹大小的最快方法是什么?

时间:2010-05-19 21:29:49

标签: c# .net filesystems

我需要计算数百个文件夹的大小,有些将是10MB,有些可能是10GB,我需要一种超快速的方法来使用C#获取每个文件夹的大小。

我希望最终结果是:

Folder1 10.5GB

Folder2 230MB

Folder3 1.2GB

...

9 个答案:

答案 0 :(得分:34)

添加对Microsoft Scripting Runtime的引用并使用:

Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
Scripting.Folder folder = fso.GetFolder([folder path]);
Int64 dirSize = (Int64)folder.Size;

如果你只需要这个尺寸,那么很多比递归更快。

答案 1 :(得分:13)

好的,这很可怕,但是......

使用名为dirsize.bat的递归dos批处理文件:

@ECHO OFF
IF %1x==x GOTO start
IF %1x==DODIRx GOTO dodir
SET CURDIR=%1
FOR /F "usebackq delims=" %%A IN (`%0 DODIR`) DO SET ANSWER=%%A %CURDIR%
ECHO %ANSWER%
GOTO end
:start
FOR /D %%D IN (*.*) DO CALL %0 "%%D"
GOTO end
:dodir
DIR /S/-C %CURDIR% | FIND "File(s)"
GOTO end
:end

注意:第5行的最后一个“%% A”后面应该有一个制表符,而不是空格。

这是您正在寻找的数据。它会很快地完成数千个文件。事实上,它可以在不到2秒的时间内完成我的整个硬盘驱动器。

执行此dirsize | sort /R /+25之类的文件,以便查看最先列出的最大目录。

祝你好运。

答案 2 :(得分:2)

在.Net中没有简单的方法可以做到这一点;你将不得不遍历每个文件和子目录。 请参阅示例here,了解它是如何完成的。

答案 3 :(得分:1)

你可以这样做,但是在获取文件夹大小方面没有fast = true设置,你必须加上文件大小。

    private static IDictionary<string, long> folderSizes;

    public static long GetDirectorySize(string dirName)
    {
        // use memoization to keep from doing unnecessary work
        if (folderSizes.ContainsKey(dirName))
        {
            return folderSizes[dirName];
        }

        string[] a = Directory.GetFiles(dirName, "*.*");

        long b = 0;
        foreach (string name in a)
        {
            FileInfo info = new FileInfo(name);
            b += info.Length;
        }

        // recurse on all the directories in current directory
        foreach (string d in Directory.GetDirectories(dirName))
        {
            b += GetDirectorySize(d);
        }

        folderSizes[dirName] = b;
        return b;
    }

    static void Main(string[] args)
    {
        folderSizes = new Dictionary<string, long>();
        GetDirectorySize(@"c:\StartingFolder");
        foreach (string key in folderSizes.Keys)
        {
            Console.WriteLine("dirName = " + key + " dirSize = " + folderSizes[key]);
        }

        // now folderSizes will contain a key for each directory (starting
        // at c:\StartingFolder and including all subdirectories), and
        // the dictionary value will be the folder size
    }

答案 4 :(得分:1)

如果您右键单击一个大目录,那么您可以看到属性需要花费大量时间来计算大小......我认为我们不能在这方面击败MS。你可以做的一件事是索引目录/子目录的大小,如果你要反复计算它们......那将大大提高速度。

你可以使用这样的东西来递归计算C#中的目录大小

static long DirSize(DirectoryInfo directory)
{
    long size = 0;

    FileInfo[] files = directory.GetFiles();
    foreach (FileInfo file in files)
    {
        size += file.Length;
    }

    DirectoryInfo[] dirs = directory.GetDirectories();

    foreach (DirectoryInfo dir in dirs)
    {
        size += DirSize(dir);
    }

    return size;
}

答案 5 :(得分:1)

Dot Net Pearls的方法类似于此处描述的方法。令人惊讶的是,System.IO.DirectoryInfo类没有方法来执行此操作,因为它似乎是一种常见的需求,如果不对每个文件系统对象执行本机/托管转换,它可能会更快。我认为如果速度是关键,那么编写一个非托管对象来进行此计算,然后从托管代码中为每个目录调用一次。

答案 6 :(得分:1)

4.0-4.5框架上最快的方法,我可以找到计算文件大小及其在磁盘上的计数:

using System.IO;
using System.Threading;
using System.Threading.Tasks;

class FileCounter
{
  private readonly int _clusterSize;
  private long _filesCount;
  private long _size;
  private long _diskSize;

  public void Count(string rootPath)
  {
    // Enumerate files (without real execution of course)
    var filesEnumerated = new DirectoryInfo(rootPath)
                              .EnumerateFiles("*", SearchOption.AllDirectories);
    // Do in parallel
    Parallel.ForEach(filesEnumerated, GetFileSize);
  }

  /// <summary>
  /// Get real file size and add to total
  /// </summary>
  /// <param name="fileInfo">File information</param>
  private void GetFileSize(FileInfo fileInfo)
  {
    Interlocked.Increment(ref _filesCount);
    Interlocked.Add(ref _size, fileInfo.Length);
  }
}

var fcount = new FileCounter("F:\\temp");
fcount.Count();

这种方法对我来说是我在.net平台上找到的最好的方法。顺便说一下,如果你需要计算磁盘上的簇大小和实际大小,你可以做下一步:

using System.Runtime.InteropServices;

private long WrapToClusterSize(long originalSize)
    {
        return ((originalSize + _clusterSize - 1) / _clusterSize) * _clusterSize;
    }

private static int GetClusterSize(string rootPath)
    {
        int sectorsPerCluster = 0, bytesPerSector = 0, numFreeClusters = 0, totalNumClusters = 0;
        if (!GetDiskFreeSpace(rootPath, ref sectorsPerCluster, ref bytesPerSector, ref numFreeClusters,
                              ref totalNumClusters))
        {
            // Satisfies rule CallGetLastErrorImmediatelyAfterPInvoke.
            // see http://msdn.microsoft.com/en-us/library/ms182199(v=vs.80).aspx
            var lastError = Marshal.GetLastWin32Error();
            throw new Exception(string.Format("Error code {0}", lastError));
        }
        return sectorsPerCluster * bytesPerSector;
    }
[DllImport(Kernel32DllImport, SetLastError = true)]
    private static extern bool GetDiskFreeSpace(
        string rootPath,
        ref int sectorsPerCluster,
        ref int bytesPerSector,
        ref int numFreeClusters,
        ref int totalNumClusters);

当然,您需要在第一个代码部分重写GetFileSize():

private long _diskSize;
private void GetFileSize(FileInfo fileInfo)
    {
        Interlocked.Increment(ref _filesCount);
        Interlocked.Add(ref _size, fileInfo.Length);
        Interlocked.Add(ref _diskSize, WrapToClusterSize(fileInfo.Length));
    }

答案 7 :(得分:0)

this link中有一些线索(尽管它是在Python中)来自遇到类似性能问题的人。您可以尝试调用Win32 API来查看性能是否有所改善,但最后您将遇到同样的问题:任务只能这么快完成,如果您必须执行很多任务有些时候,需要很多时间。你能详细介绍一下你正在做什么吗?它可能会帮助人们想出一个启发式或一些秘籍来帮助你。如果您正在进行大量计算,是否要缓存结果?

答案 8 :(得分:0)

我很确定这会很慢, 但我会这样写:

using System.IO;

long GetDirSize(string dir) {
   return new DirectoryInfo(dir)
      .GetFiles("", SearchOption.AllDirectories)
      .Sum(p => p.Length);
}