C # Как рекурсивно зациклить большой набор папок и файлов, не используя огромный объем памяти - PullRequest
3 голосов
/ 22 ноября 2010

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

т.е.

start > ReadFiles(C:\music\);

ReadFiles(path){
   foreach(file)
      save to index;

   foreach(directory)
      ReadFiles(directory);
}

Это работает нормально, но во время работы программы объем используемой памяти растет и растет и ... наконец-то моей системе не хватает памяти.

У кого-нибудь есть лучший подход, который не требует 4 ГБ ОЗУ для выполнения этой задачи?

С наилучшими пожеланиями, Тыс

Ответы [ 5 ]

9 голосов
/ 22 ноября 2010

Решение на основе очереди Алксандра должно работать нормально.

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

void ReadFiles(string path)
{
    IEnumerable<string> files =
        Directory.EnumerateFiles(
            path,
            "*",
            SearchOption.AllDirectories); // search recursively

    foreach(string file in files)
        SaveToIndex(file);
}
2 голосов
/ 22 ноября 2010

Проверяли ли вы записи . и .., которые отображаются в каждом каталоге, кроме корневого?

Если вы не пропустите их, у вас будет бесконечный цикл.

1 голос
/ 22 ноября 2010

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

Примерно так:

Queue<string> dirs = new Queue<string>();
dirs.Enqueue("basedir");
while(dirs.Count > 0) {
    foreach(directory)
        dirs.Enqueue(directory);
    ReadFiles();
}
0 голосов
/ 21 марта 2018

Это могут быть соединительные папки, которые приводят к бесконечному циклу при выполнении рекурсии, но я не уверен, проверьте это и убедитесь сами. Ссылка: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink

0 голосов
/ 24 ноября 2013

Остерегайтесь, однако, что EnumerateFiles () прекратит работу, если у вас нет доступа к файлу, или если путь слишком длинный или если произойдет какое-то другое исключение.Вот что я сейчас использую для решения этих проблем:

public static List<string> getFiles(string path, List<string> files)
{
    IEnumerable<string> fileInfo = null;
    IEnumerable<string> folderInfo = null;
    try
    {
        fileInfo = Directory.EnumerateFiles(str);
    }
    catch
    {

    }
    if (fileInfo != null)
    {
        files.AddRange(fileInfo);
        //recurse through the subfolders
        fileInfo = Directory.EnumerateDirectories(str);
        foreach (string s in folderInfo)
        {
            try
            {
                getFiles(s, files);
            }
            catch
            {

            }
        }
    }
    return files;
}

Пример использования:

List<string> files = new List<string>();
files = folder.getFiles(path, files);

Мое решение основано на коде на этой странице: http://msdn.microsoft.com/en-us/library/vstudio/bb513869.aspx.

Обновление: гораздо более быстрый способ рекурсивного получения файлов можно найти по адресу http://social.msdn.microsoft.com/Forums/vstudio/en-US/ae61e5a6-97f9-4eaa-9f1a-856541c6dcce/directorygetfiles-gives-me-access-denied?forum=csharpgeneral. Использование стека является новым для меня (я даже не знал, что он существует), но метод, похоже, работает.По крайней мере, в нем перечислены все файлы в моем разделе C и D без ошибок.

...