Лучший способ перебирать папки и подпапки

Как лучше всего перебирать папки и подпапки, чтобы получить размер файла, общее количество файлов и общий размер папки в каждой папке, начиная с указанного места?


person Rod    schedule 03.03.2011    source источник
comment
Всего два слова: foreach и рекурсия..   -  person Andrew Orsich    schedule 03.03.2011
comment
@ Bugai13 - это хорошее предложение для домашнего задания по CS, но инфраструктура .Net уже включает эту функциональность. Кроме того, переход от итерации по коллекциям/перечислениям к запросам коллекций/перечислений или даже предоставление коллекции/перечислимой работы — это правильный способ решить эту проблему в современном контексте.   -  person Ritch Melton    schedule 03.03.2011
comment
пожалуйста, исправьте опечатку в заголовке: итерируйте и сделайте первую букву заглавной.   -  person HuBeZa    schedule 03.03.2011
comment
@Pekka Сначала я хотел изучить разные способы, но, думаю, я останусь на С#   -  person Rod    schedule 03.03.2011


Ответы (6)


Используйте Directory.GetFiles(). В нижней части этой страницы приведен полностью рекурсивный пример.

Примечание. Используйте приведенный ниже ответ Криса Данауэя для более современного подхода при использовании .NET 4 и выше.

// For Directory.GetFiles and Directory.GetDirectories
// For File.Exists, Directory.Exists
using System;
using System.IO;
using System.Collections;

public class RecursiveFileProcessor 
{
    public static void Main(string[] args) 
    {
        foreach(string path in args) 
        {
            if(File.Exists(path)) 
            {
                // This path is a file
                ProcessFile(path); 
            }               
            else if(Directory.Exists(path)) 
            {
                // This path is a directory
                ProcessDirectory(path);
            }
            else 
            {
                Console.WriteLine("{0} is not a valid file or directory.", path);
            }        
        }        
    }

    // Process all files in the directory passed in, recurse on any directories 
    // that are found, and process the files they contain.
    public static void ProcessDirectory(string targetDirectory) 
    {
        // Process the list of files found in the directory.
        string [] fileEntries = Directory.GetFiles(targetDirectory);
        foreach(string fileName in fileEntries)
            ProcessFile(fileName);

        // Recurse into subdirectories of this directory.
        string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
        foreach(string subdirectory in subdirectoryEntries)
            ProcessDirectory(subdirectory);
    }
    
    // Insert logic for processing found files here.
    public static void ProcessFile(string path) 
    {
        Console.WriteLine("Processed file '{0}'.", path);       
    }
}
person Lloyd    schedule 03.03.2011
comment
Одно предостережение: Directory.GetFiles() может быть чрезвычайно медленным с каталогами, содержащими большое количество файлов (от 10 до 100 тысяч). В этих случаях самый быстрый способ, который я нашел до сих пор, - это запустить процесс для запуска команды dir и перенаправить вывод и проанализировать его (или передать в файл и прочитать его). Конечно, я не рассматриваю это, если не ожидаю более 50 000 файлов в одном каталоге. - person quentin-starin; 14.05.2011
comment
На самом деле может быть быстрее вызвать FindFirstFile и т. д. вместо использования dir, хотя я уверен, что .NET все равно с этим справляется. - person Lloyd; 15.01.2013

Если вы используете .NET 4, вы можете использовать методы System.IO.DirectoryInfo.EnumerateDirectories и System.IO.DirectoryInfo.EnumerateFiles. Если вы используете метод Directory.GetFiles, как рекомендовали другие сообщения, вызов метода не вернется, пока он не получит ВСЕ записи. Это может занять много времени, если вы используете рекурсию.

Из документации:

Методы EnumerateFiles и GetFiles различаются следующим образом:

  • Когда вы используете EnumerateFiles, вы можете начать перечисление коллекции объектов FileInfo до того, как будет возвращена вся коллекция.
  • Когда вы используете GetFiles, вы должны дождаться возврата всего массива объектов FileInfo, прежде чем вы сможете получить доступ к массиву.

Поэтому, когда вы работаете с большим количеством файлов и каталогов, EnumerateFiles может быть более эффективным.

person Chris Dunaway    schedule 03.03.2011
comment
Пришлось пропустить дюжину примеров использования GetDirectory(), чтобы найти этот. С каталогами ›50k это было слишком медленно. Спасибо за редкий пример, который спас мой день. - person krowe2; 14.08.2018

Для перебора всех каталогов, подпапок и файлов, независимо от того, сколько подпапок и файлов.

string [] filenames;
 fname = Directory.GetFiles(jak, "*.*", SearchOption.AllDirectories).Select(x => Path.GetFileName(x)).ToArray();

затем из массива вы можете получить то, что хотите, через цикл или как хотите.

person safi    schedule 03.03.2011
comment
Это приведет к бесконечному циклу, если в структуре вашей папки есть цикл: см. msdn.microsoft. com/en-us/library/ms143448.aspx - person Anthony Wieser; 02.10.2013

Для просмотра файлов и папок обычно используются DirectoryInfo и FileInfo. Тип FileInfo имеет свойство Length, которое возвращает размер файла в байтах.

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

person Rune Grimstad    schedule 03.03.2011

Обратите внимание, что вам нужно будет выполнить проверки проверки.

string[] fileNames = Directory.GetFiles("c:\\", "*.*", SearchOption.AllDirectories);
int fileCount = fileNames.Count();
long fileSize = fileNames.Select(file => new FileInfo(file).Length).Sum(); // in bytes
person HuBeZa    schedule 03.03.2011
comment
Какой тип проверочных проверок - person Rod; 03.03.2011
comment
@rod: проверьте, если Directory.Exists (иначе DirectoryNotFoundException). Я не могу думать ни о чем другом, но, возможно, я что-то упустил. - person HuBeZa; 03.03.2011

Вот пример использования предложения Питера выше и рекурсии.

using System;
using System.IO;

namespace FileSystemUtils
{
    class Program
    {
        static void Main(string[] args)
        {
            string folderPath = "C:\\docs";

            DirectoryInfo startDir = new DirectoryInfo(folderPath);

            RecurseFileStructure recurseFileStructure = new RecurseFileStructure();
            recurseFileStructure.TraverseDirectory(startDir);
        }

        public class RecurseFileStructure
        {
            public void TraverseDirectory(DirectoryInfo directoryInfo)
            {
                var subdirectories = directoryInfo.EnumerateDirectories();

                foreach (var subdirectory in subdirectories)
                {
                    TraverseDirectory(subdirectory);
                }

                var files = directoryInfo.EnumerateFiles();

                foreach (var file in files)
                {
                    HandleFile(file);
                }
            }

            void HandleFile(FileInfo file)
            {
                Console.WriteLine("{0}", file.Name);
            }
        }
    }
}
person S4NT14G0    schedule 23.10.2019