Быстро оценить количество подпапок - PullRequest
3 голосов
/ 20 июня 2011

Мое приложение C # 3.0 должно перемещаться по папкам и делать что-то внутри.Чтобы показать значительный прогресс, мне нужно знать общее количество папок.

Если я использую опцию Directory.GetDirectories с AllDirectories, это займет очень много времени на моем жестком диске 2 ТБ с папками около 100 КБ, идолжен представить прогресс даже для этой операции!Единственное, что я могу сделать - это использовать рекурсив Directory.GetDirectories и предоставить пользователю несколько уже найденных каталогов.Однако это занимает даже больше времени, чем первый подход.

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

Ответы [ 5 ]

2 голосов
/ 20 июня 2011

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

Таким образом,пользователь будет знать, что приложение работает в фоновом режиме, пока все происходит.

1 голос
/ 20 июня 2011

Подобные вещи сложно сделать.Если вы просто пытаетесь сделать приблизительную оценку для индикатора выполнения, вам не нужна большая детализация, верно?Я бы предложил вручную обходить дерево каталогов только на один или два уровня, чтобы выяснить, сколько существует подкаталогов 1-го и 2-го уровня.Затем вы можете обновлять свой индикатор выполнения каждый раз, когда вы нажимаете на один из этих подкаталогов.Это должно дать вам значимый индикатор выполнения, не затрачивая слишком много времени на вычисления.

1 голос
/ 20 июня 2011

Если вы реализуете это, вы обнаружите, что ваше первое предварительное сканирование было самым медленным, но оно ускорит следующее (полное) сканирование, потому что структура папок кэшируется.

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


Часть 2, касающаяся вопроса P / Invoke

Ваша главная цена здесь - это истинный ввод-вывод низкого уровня, накладные расходы(любой) API незначителен.

Вы, вероятно, выиграете от замены GetFiles() на EnumerateFiles() (Fx4).Больше для вашего основного цикла, чем для предварительного сканирования.

0 голосов
/ 12 октября 2012

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

Кэширования почти нет, особенно не глубоких структур, поэтому это должно работать почти так же быстро, как и непосредственное перечисление.

public static IEnumerable<Tuple<string, float>> EnumerateFiles (string root)
{
    var files = Directory.GetFiles (root);
    var dirs = Directory.GetDirectories (root);
    var fact = 1f / (float) (dirs.Length + 1); // this makes for a rough estimate

    for (int i = 0; i < files.Length; i++) {
        var file = files[i];
        var f = (float) i / (float) files.Length;
        f *= fact;
        yield return new Tuple<string, float> (file, f);
    }

    for (int i = 0; i < dirs.Length; i++) {
        var dir = dirs[i];
        foreach (var tuple in EnumerateFiles (dir)) {
            var f = tuple.Item2;
            f *= fact;
            f += (i + 1) * fact;
            yield return new Tuple<string, float> (tuple.Item1, f);
        }
    }
}
0 голосов
/ 20 июня 2011

Исследуйте API-интерфейсы FindFirstFile и FindNextFile .Я думаю, они будут работать быстрее в вашем случае

...