Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Узнать размер директории


Автор: DoZENT 20.6.2007, 14:24
Как бы мне узнать размер заданной директории на C#? Тупо перебрать все вложенные файлы? Может функция какая есть...?

Автор: Pankon 20.6.2007, 16:59
Код

        public static int GetCountOfFileInDirectory(string directory)
        {
            return Directory.GetFiles(directory).Length;
        }

Автор: DoZENT 20.6.2007, 18:27
Эта функция возвращает число файлов в заданной директории. А мне нужен ее размер.

Автор: Void 20.6.2007, 19:36
Код

static long GetDirectorySize(string directory)
{
    long result = 0;
    foreach (string file in Directory.GetFiles(
            directory, "*", SearchOption.AllDirectories))
    {
        FileInfo f = new FileInfo(file);
        result += f.Length;
    }
    return result;
}

Только надо учесть, что при большом количестве файлов будет создавать большой массив, занимая много памяти. Способов перебрать файлы поочерёдно без P/Invoke в .NET нет.

Автор: ivashkanet 21.6.2007, 09:01
Void, а если рекурсию забомбить? Памяти меньше съест. Тем более я считал, что это стандартный подход  smile 

DoZENT, в общем: нет такой стандартной функции  smile 

Автор: Exception 21.6.2007, 10:09
В Mono сделано так (http://www.google.com/codesearch?hl=ru&q=+lang:c%23+get+directory+size+show:IF3wPwFUdBI:n-Xzi20BTUI:6gP-pSHgJzU&sa=N&cd=2&ct=rc&cs_p=http://www.go-mono.com/archive/mcs-0.29.tar.gz&cs_f=mcs-0.29/class/corlib/System.IO.IsolatedStorage/IsolatedStorageInfo.cs#a0#a0)
Код
internal static ulong GetDirectorySize (Directory 
Info di)
{
    ulong size = 0;
    foreach (FileInfo fi in di.GetFiles ())
        size += (ulong) fi.Length;
    foreach (Directory 
Info d in di.GetDirectories())
        size += GetDirectorySize 
(d);
    return size;
}

Автор: ivashkanet 21.6.2007, 10:36
Exception, т.е. рекурсивно ;-)

Автор: Stepan_Lameroff 21.6.2007, 12:28
Всегда есть выбор  smile 
Код

        static long GetDirSize(string root, bool isRecursive)
        {
            long size = 0;
            if (!Directory.Exists(root))
                return size;

            Queue<string> queue = new Queue<string>();
            queue.Enqueue(root);

            while (queue.Count > 0)
            {
                string currDir = queue.Dequeue();
                if (isRecursive)
                {
                    foreach (string dir in Directory.GetDirectories(currDir))
                        queue.Enqueue(dir);
                }

                foreach (string file in Directory.GetFiles(currDir))
                    size += new FileInfo(file).Length;
            }
            return size;
        }

Автор: Void 21.6.2007, 13:36
Выбора нет. Если в директории плоско лежат миллион файлов, массив все равно создасться.
Аналога FindFirstFile/FindNextFile (opendir/readdir или ещё лучше ftw) нет.

Но, впрочем, не суть важно smile Не думаю, что автор собирается проверять размер %WINDIR% на регулярной основе smile

Автор: DoZENT 21.6.2007, 20:12
Цитата

Но, впрочем, не суть важно

Да нет, все-таки важно smile Я прогу пишу, которая должна динамически для каждого каталога размер выводить... Это мой первый проект на C#, поэтому подскажите, pls, какая из приведенных выше функций будет работать быстрее?

Автор: Stepan_Lameroff 21.6.2007, 20:38
Вот Вам Native решение:
Код

    public const int MAX_PATH = 260;
    public const int MAX_ALTERNATE = 14;

    [StructLayout(LayoutKind.Sequential)]
        public struct FILETIME {
        public uint dwLowDateTime;
        public uint dwHighDateTime;
     }; 

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] 
    public struct WIN32_FIND_DATA {
        public FileAttributes dwFileAttributes;
        public FILETIME ftCreationTime; 
        public FILETIME ftLastAccessTime; 
        public FILETIME ftLastWriteTime; 
        public int nFileSizeHigh;
        public int nFileSizeLow;
        public int dwReserved0;
        public int dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)] 
        public string cFileName; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)] 
        public string cAlternate; 
    }

    [DllImport("kernel32", CharSet=CharSet.Unicode)] 
    public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32", CharSet=CharSet.Unicode)] 
    public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

    private long RecurseDirectory(string directory, int level, out int files, out int folders) {
        IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        long size = 0;
        files = 0;
        folders = 0;
        Kernel32.WIN32_FIND_DATA findData;

        IntPtr findHandle;

        findHandle = Kernel32.FindFirstFile(@"\\?\" + directory + @"\*", out findData);
        if (findHandle != INVALID_HANDLE_VALUE) {

            do {
                if ((findData.dwFileAttributes & FileAttributes.Directory) != 0) {

                    if (findData.cFileName != "." && findData.cFileName != "..") {
                        folders++;

                        int subfiles, subfolders;
                        string subdirectory = directory + (directory.EndsWith(@"\") ? "" : @"\") + 
                            findData.cFileName;
                        if (level != 0)  // allows -1 to do complete search.
                            {
                        size += RecurseDirectory(subdirectory, level - 1, out subfiles, out subfolders);

                        folders += subfolders;
                        files += subfiles;
                        }
                    }
                }
                else {
                    // File
                    files++;

                    size += (long)findData.nFileSizeLow + (long)findData.nFileSizeHigh * 4294967296;
                }
            } 
            while (Kernel32.FindNextFile(findHandle, out findData));
            Kernel32.FindClose(findHandle);

        }

        return size;
    }

Взято http://www.pinvoke.net/default.aspx/kernel32/FindFirstFile.html.
У меня результаты тестов были такие:
Цитата

GetDirSize - Native. Dir to scan: C:\
Size: 17,1 GB
Time: 11s
GetDirSize - Managed. Dir to scan: C:\
Size: 17,1 GB
Time: 11s

Выбирать Вам  smile 

Автор: ivashkanet 22.6.2007, 09:29
Stepan_Lameroff, а память? 
А 
Цитата(Void @  21.6.2007,  13:36 Найти цитируемый пост)
Если в директории плоско лежат миллион файлов, массив все равно создасться.
?

DoZENT, ИМХО, используй код Exception-а. Он проще.
Хотя код Stepan_Lameroff-а (тот, который с очередью), мне очень понравился своей идеей избавления от рекурсии, но я бы его не использовал. Ибо нужна смекалка, чтобы в ним разобраться, а код Exception-а стандартный подход.

Автор: Stepan_Lameroff 22.6.2007, 11:19
Памяти, естественно, managed method кушает поболее (массивы  smile ).
Да и процессор он нагружает больше.
Цитата

GetDirSize - Native. Dir to scan: D:\
GetDirSize - Native:Start. Total Memory: 149228
Size: 19,6 GB
Time: 2m0s
GetDirSize - Native:Exit. Total Memory: 279748

Call GC.Collect()

GetDirSize - Managed. Dir to scan: D:\
GetDirSize - Managed:Start. Total Memory: 154508
Size: 19,6 GB
Time: 2m51s
GetDirSize - Managed:Exit. Total Memory: 5812980

Автор: ivashkanet 22.6.2007, 11:31
smile 
Stepan_Lameroff, а что у тя за профайлер? Дай поиграться  smile  smile

Добавлено через 4 минуты и 32 секунды
Цитата(Stepan_Lameroff @  22.6.2007,  11:19 Найти цитируемый пост)
Да и процессор он нагружает больше.

Т.е. больше всего тянут операции ввода/вывода (что логично). А само вычисление на твоем компе происходит примерно одинаково.

Автор: Stepan_Lameroff 22.6.2007, 12:34
Я думаю, такой есть у всех  smile 
http://www.microsoft.com/downloads/details.aspx?FamilyID=a362781c-3870-43be-8926-862b40aa0cd0&displaylang=en

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)