Подтвердить что ты не робот

Каков самый быстрый способ рассчитать размер папок Windows?

Мне нужно рассчитать размер сотен папок, некоторые из них будут 10 МБ, может быть, 10 ГБ, мне нужен супер быстрый способ получить размер каждой папки с помощью С#.

Мой конечный результат, мы надеемся, будет следующим:

Папка1 10.5GB

Папка2 230 МБ

Папка3 1.2GB

...

4b9b3361

Ответ 1

Нет простого способа сделать это в .Net; вам придется перебирать каждый файл и субдир. См. Примеры здесь, чтобы узнать, как это делается.

Ответ 2

Добавьте ссылку на исполняемый файл Microsoft Scripting Runtime и используйте:

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

Если вам нужен только размер, это намного быстрее, чем рекурсия.

Ответ 3

Хорошо, это ужасно, но...

Используйте рекурсивный пакетный файл dos, который называется dirsize.bat:

@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

Примечание. После окончательного "%% A" в строке 5 должен быть символ табуляции, а не пробелы.

Это данные, которые вы ищете. Он будет делать тысячи файлов довольно быстро. Фактически, он делает весь ваш жесткий диск менее чем за 2 секунды.

Выполните файл, подобный этому dirsize | sort /R /+25, чтобы увидеть первую в списке первую папку.

Удачи.

Ответ 4

Вы можете сделать что-то вроде этого, но при настройке папок нет быстрых = истинных настроек, вам нужно добавить размеры файлов.

    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
    }

Ответ 5

Если вы щелкните правой кнопкой мыши по большому каталогу, тогда свойства вы увидите, что для вычисления размера требуется значительное количество времени... Я не думаю, что мы можем победить MS в этом. Одна вещь, которую вы можете сделать, это индексировать размеры каталогов/поддиректоров, если вы собираетесь их вычислять снова и снова... это значительно увеличило бы скорость.

Вы можете использовать что-то вроде этого, чтобы вычислить размер каталога в рекурсивно С#

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

Ответ 6

Dot Net Pearls имеет метод, аналогичный описанному здесь. Удивительно, что класс System.IO.DirectoryInfo не имеет способа сделать это, поскольку он кажется общей потребностью и, вероятно, будет быстрее сделать это, не выполняя собственный/управляемый переход на каждый объект файловой системы. Я думаю, что если скорость - это ключевая вещь, написание не управляемого объекта для этого вычисления, а затем вызов его один раз для каждого каталога из управляемого кода.

Ответ 7

Самый быстрый подход к фреймворку 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. Btw, если вам нужно рассчитать размер кластера и реальный размер на диске, вы можете сделать следующее:

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

Ответ 8

Есть несколько ссылок в эта ссылка (хотя на Python) от человека, который сталкивается с подобными проблемами производительности. Вы можете попробовать перейти на Win32 API, чтобы увидеть, улучшена ли производительность, но в конце вы столкнетесь с одной и той же проблемой: задача может быть выполнена только так быстро, и если вам нужно многократно выполнять эту задачу, это займет много времени. Можете ли вы дать более подробную информацию о том, для чего вы это делаете? Это может помочь людям придумать эвристику или некоторые читы, которые помогут вам. Если вы много делаете это вычисление, выполняете ли вы кеширование результатов?

Ответ 9

Я совершенно уверен, что это будет медленно, как черт, но я бы написал его вот так:

using System.IO;

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