Как лучше всего рассчитать размер каталога в .NET? - PullRequest
64 голосов
/ 22 января 2009

Я написал следующую процедуру для ручного обхода каталога и вычисления его размера в C # /. NET:


protected static float CalculateFolderSize(string folder)
{
    float folderSize = 0.0f;
    try
    {
        //Checks if the path is valid or not
        if (!Directory.Exists(folder))
            return folderSize;
        else
        {
            try
            {
                foreach (string file in Directory.GetFiles(folder))
                {
                    if (File.Exists(file))
                    {
                        FileInfo finfo = new FileInfo(file);
                        folderSize += finfo.Length;
                    }
                }

                foreach (string dir in Directory.GetDirectories(folder))
                    folderSize += CalculateFolderSize(dir);
            }
            catch (NotSupportedException e)
            {
                Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
            }
        }
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
    }
    return folderSize;
}

У меня есть приложение, которое запускает эту процедуру несколько раз для большого количества папок. Мне интересно, есть ли более эффективный способ расчета размера папки с .NET? Я не видел ничего конкретного в рамках. Должен ли я использовать P / Invoke и Win32 API? Как наиболее эффективно рассчитать размер папки в .NET?

Ответы [ 20 ]

4 голосов
/ 22 января 2009

Это лучший способ рассчитать размер каталога. Только другой способ все равно будет использовать рекурсию, но будет немного проще в использовании и не так гибок.

float folderSize = 0.0f;
FileInfo[] files = Directory.GetFiles(folder, "*", SearchOption.AllDirectories);
foreach(FileInfo file in files) folderSize += file.Length;
4 голосов
/ 17 июня 2015

Оказывается, следующий метод выполняет вашу задачу быстрее, чем рекурсивная функция:

long size = 0;
DirectoryInfo dir = new DirectoryInfo(folder);
foreach (FileInfo fi in dir.GetFiles("*.*", SearchOption.AllDirectories))
{
   size += fi.Length;
}

Простой тест консольного приложения показывает, что этот цикл суммирует файлы быстрее, чем рекурсивная функция, и дает тот же результат. И вы, вероятно, хотите использовать методы LINQ (например, Sum ()) для сокращения этого кода.

3 голосов
/ 11 сентября 2014
public static long GetDirSize(string path)
{
    try
    {
        return Directory.EnumerateFiles(path).Sum(x => new FileInfo(x).Length)  
            +
               Directory.EnumerateDirectories(path).Sum(x => GetDirSize(x));
    }
    catch
    {
        return 0L;
    }
}
3 голосов
/ 21 августа 2018
Directory.GetFiles(@"C:\Users\AliBayat","*.*",SearchOption.AllDirectories)
.Select (d => new FileInfo(d))
.Select (d => new { Directory = d.DirectoryName,FileSize = d.Length} )
.ToLookup (d => d.Directory )
.Select (d => new { Directory = d.Key,TotalSizeInMB =Math.Round(d.Select (x =>x.FileSize)
.Sum () /Math.Pow(1024.0,2),2)})
.OrderByDescending (d => d.TotalSizeInMB).ToList();

Вызов GetFiles с SearchOption.AllDirectories возвращает полное имя всех файлов во всех subdirectories указанного каталога. ОС представляет размер файлов в байтах. Вы можете получить размер файла из его свойства Length. Разделив его на 1024 с точностью до 2, вы получите размер файла в мегабайтах. Поскольку каталог / папка может содержать много файлов, d.Select(x => x.FileSize) возвращает набор размеров файлов, измеренных в мегабайтах. Последний вызов Sum() определяет общий размер файлов в указанном каталоге.

2 голосов
/ 22 января 2009

Что касается наилучшего алгоритма, то, вероятно, вы все правильно поняли. Я бы порекомендовал вам распутать рекурсивную функцию и использовать свой собственный стек (помните, что переполнение стека - это конец света в приложении .Net 2.0+, исключение не может быть перехвачено IIRC).

Самым важным является то, что если вы используете его в любой форме пользовательского интерфейса, поместите его в рабочий поток, который сообщает потоку пользовательского интерфейса с обновлениями.

2 голосов
/ 08 августа 2013

Чтобы повысить производительность, вы можете использовать Task Parallel Library (TPL). Вот хороший пример: Расчет размера файла каталога - как сделать это быстрее?

Я не тестировал его, но автор говорит, что он в 3 раза быстрее, чем не многопоточный метод ...

1 голос
/ 09 сентября 2016

Самый быстрый способ, которым я пришел, - это использование EnumerateFiles с SearchOption.AllDirectories. Этот метод также позволяет обновлять пользовательский интерфейс, просматривая файлы и подсчитывая размер. Длинные пути не вызывают проблем, так как FileInfo или DirectoryInfo не пытались создать для длинного имени пути. При перечислении файлов, даже если имя файла длинное, FileInfo, возвращаемое EnumerateFiles, не вызывает проблем, если имя начального каталога не слишком длинное. Все еще существует проблема с UnauthorizedAccess.

    private void DirectoryCountEnumTest(string sourceDirName)
    {
        // Get the subdirectories for the specified directory.
        long dataSize = 0;
        long fileCount = 0;
        string prevText = richTextBox1.Text;

        if (Directory.Exists(sourceDirName))
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            foreach (FileInfo file in dir.EnumerateFiles("*", SearchOption.AllDirectories))
            {
                fileCount++;
                try
                {
                    dataSize += file.Length;
                    richTextBox1.Text = prevText + ("\nCounting size: " + dataSize.ToString());
                }
                catch (Exception e)
                {
                    richTextBox1.AppendText("\n" + e.Message);
                }
            }
            richTextBox1.AppendText("\n files:" + fileCount.ToString());
        }
    }
0 голосов
/ 18 мая 2019

Я знаю, что это не решение .net, но оно приходит в любом случае. Может быть, это пригодится людям, которые имеют Windows 10 и хотят более быстрого решения. Например, если вы запустите эту команду в командной строке или нажмете winKey + R:

bash -c "du -sh /mnt/c/Users/; sleep 5"    

sleep 5 означает, что у вас есть время, чтобы увидеть результаты, и окна не закрываются

На моем компьютере отображается:

enter image description here

Обратите внимание, в конце, как он показывает 85G (85 гигабайт). Это ужин по сравнению с .Net. Если вы хотите увидеть размер более точно, удалите h, что означает удобочитаемое человеком.

Так что просто сделайте что-то вроде Processes.Start("bash",... arguments) Это не точный код, но вы поняли идею.

0 голосов
/ 26 февраля 2019

Это приложение командной строки .NET рассчитывает размеры каталогов для заданного пути:

https://github.com/garethrbrown/folder-size

Ключевой метод - это тот, который рекурсивно проверяет подкаталоги для определения общего размера.

private static long DirectorySize(SortDirection sortDirection, DirectoryInfo directoryInfo, DirectoryData directoryData)
{
        long directorySizeBytes = 0;

        // Add file sizes for current directory

        FileInfo[] fileInfos = directoryInfo.GetFiles();

        foreach (FileInfo fileInfo in fileInfos)
        {
            directorySizeBytes += fileInfo.Length;
        }

        directoryData.Name = directoryInfo.Name;

        directoryData.SizeBytes += directorySizeBytes;

        // Recursively add subdirectory sizes

        DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();

        foreach (DirectoryInfo di in subDirectories)
        {
            var subDirectoryData = new DirectoryData(sortDirection);

            directoryData.DirectoryDatas.Add(subDirectoryData);

            directorySizeBytes += DirectorySize(sortDirection, di, subDirectoryData);
        }

        directoryData.SizeBytes = directorySizeBytes;

        return directorySizeBytes;
    }
}
0 голосов
/ 07 сентября 2018

Альтернатива однолинейному решению Трикалдарши. (Это избавляет от необходимости создавать объекты FileInfo)

long sizeInBytes = Directory.EnumerateFiles("{path}","*", SearchOption.AllDirectories).Sum(fileInfo => fileInfo.Length);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...