C # - Как быстро и оптимизированно перечислить файлы в подкаталоге

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

Я использую .NET 3.5, поэтому не могу использовать перечислитель :-(

        ******************* Main *************
        DirectoryInfo dir = new DirectoryInfo(path);
        DirectoryInfo[] subDir = dir.GetDirectories();
        foreach (DirectoryInfo di in subDir) //call for each sub directory
        {
             PopulateList(di.FullName, false);
        }

        *******************************************
        static void PopulateList(string directory, bool IsRoot)
        {

            System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + "dir /s/b \"" + directory + "\"");
            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.UseShellExecute = false;
            procStartInfo.CreateNoWindow = true;
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo = procStartInfo;
            proc.Start();

            string fileName = directory.Substring(directory.LastIndexOf('\\') + 1);
            StreamWriter writer = new StreamWriter(fileName + ".lst");

            while (proc.StandardOutput.EndOfStream != true)
            {
                 writer.WriteLine(proc.StandardOutput.ReadLine());
                 writer.Flush();
            }
            writer.Close();
        }

person Mayur J    schedule 29.09.2011    source источник
comment
Почему вы не можете использовать Enumerator в .NET 3.5? (вы говорите using .NET 3.5 so can't use enumerator)   -  person sll    schedule 29.09.2011
comment
Directory.Enum... Я думал, что это не в 3.5   -  person Mayur J    schedule 29.09.2011


Ответы (5)


Удалите все, что связано с процессом, и попробуйте каталог . Методы GetDirectories() и Directory.GetFiles():

public IEnumerable<string> GetAllFiles(string rootDirectory)
{
    foreach(var directory in Directory.GetDirectories(
                                            rootDirectory, 
                                            "*", 
                                            SearchOption.AllDirectories))
    {
        foreach(var file in Directory.GetFiles(directory))
        {
            yield return file;
        }
    }
}

Из MSDN, SearchOption.AllDirectories:

Включает текущий каталог и все подкаталоги в операцию поиска. Этот параметр включает точки повторной обработки, такие как подключенные диски и символические ссылки в поиске.

person sll    schedule 29.09.2011
comment
Это недоступно в 3.5. - person Anton Gogolev; 29.09.2011
comment
@Anton Gogolev: спасибо, я обновил ссылку на GetDirectories() - person sll; 29.09.2011

Будет определенно быстрее использовать DirectoryInfo.GetFiles в цикле для каждого каталога вместо того, чтобы создавать множество новых процессов для чтения их вывода.

person Sergei B.    schedule 29.09.2011

С миллионами файлов вы на самом деле сталкиваетесь с ограничениями файловой системы (см. это и найдите «300,000»), так что примите это во внимание.

Что касается оптимизации, я думаю, что вы действительно хотите лениво выполнять итерацию, поэтому вам придется P/Invoke в FindFirstFile/FindNextFile.

person Anton Gogolev    schedule 29.09.2011

Ознакомьтесь с уже доступной перегрузкой Directory.GetFiles.
Например, :

var paths = Directory.GetFiles(root, "*", SearchOption.AllDirectories);

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

person default locale    schedule 29.09.2011

Предполагая, что ваши миллионы файлов распределены по нескольким подкаталогам, и вы используете .NET 4.0, вы можете посмотреть на параллельные расширения.

Использование параллельного цикла foreach для обработки списка подкаталогов может значительно ускорить работу.

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

Единственное, на что следует обратить внимание, — это убедиться, что вы ограничиваете количество одновременных процессов чем-то разумным.

person Stewart Ritchie    schedule 29.09.2011
comment
извините, я не увидел требования .net 3.5, когда сначала прочитал его - person Stewart Ritchie; 29.09.2011