проблема с перечислением файлов - PullRequest
0 голосов
/ 16 сентября 2009

Я использую VSTS 2008 + C # + .Net 3.5 для разработки консольного приложения. Мне нужно перечислить последние 50 файлов в текущей папке (чтобы прочитать содержимое файла, получить метаданные файла, такие как имя файла, время создания и т. Д.). Поскольку в текущей папке содержится около 5000 файлов, и если я использую API Directory.GetFiles, мета-данные всех 5000 файлов будут считаны в память. Я думаю, что это пустая трата, так как мне нужен только доступ к последним 50 файлам.

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

Ответы [ 2 ]

3 голосов
/ 16 сентября 2009

Это решение по-прежнему загружает метаданные обо всех файлах, но я бы сказал, что оно достаточно быстрое для большинства применений. Следующий код сообщает, что для перечисления 50 последних обновленных файлов в моем каталоге Windows \ System32 требуется около 50 мс (~ 2500 файлов). Если бы код не запускался очень часто, я бы не стал тратить время на его оптимизацию:

FileInfo[] files = (new DirectoryInfo(@"C:\WINDOWS\System32")).GetFiles();
Stopwatch sw = new Stopwatch();
sw.Start();
IEnumerable<FileInfo> recentFiles = files.OrderByDescending(
                                              fi => fi.LastWriteTime).Take(50);
List<FileInfo> list = recentFiles.ToList();
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
list.ForEach(fi => Console.WriteLine(fi.Name));

Обновление

Основываясь на обсуждении в комментариях относительно использования даты / времени в имени файла: обратите внимание, что Directory.GetFiles не загружает метаданные о файлах; он просто возвращает строковый массив с именами файлов (с другой стороны, DirectoryInfo.GetFiles возвращает массив объектов FileInfo). Таким образом, если у вас есть дата и время в именах файлов (предпочтительно в формате, пригодном для сортировки, таком как yyyyMMdd-HHmmss или что-то подобное), вы можете использовать Directory.GetFiles для получения имен файлов, сортировать по убыванию, а затем выбрать 50 первых из списка:

string[] files = Directory.GetFiles(pathToLogFiles);
IEnumerable<string> recentFiles = files.OrderByDescending(s => s).Take(50);
List<string> recentFiles = recentFiles.ToList();

Затем выполните цикл по списку и загрузите все необходимые данные из каждого файла.

1 голос
/ 16 сентября 2009

Я действительно не уверен, что это будет стоить вашего времени ... рассмотрим следующую программу:

    class DateCompare : IComparer<FileInfo>
    {
        public int Compare(FileInfo a, FileInfo b)
        { 
            int result = a.LastWriteTime.CompareTo(b.LastWriteTime);
            if (result == 0)
                return StringComparer.OrdinalIgnoreCase.Compare(a.FullName, b.FullName);
            return result;
        }
    }

    public static void Main(string[] args)
    {
        DirectoryInfo root = new DirectoryInfo("c:\\Projects\\");
        DateTime start = DateTime.Now;
        long memory = GC.GetTotalMemory(false);
        FileInfo[] allfiles = root.GetFiles("*", SearchOption.AllDirectories);
        DateTime sortStart = DateTime.Now;
        List<FileInfo> files = new List<FileInfo>(20000);
        IComparer<FileInfo> cmp = new DateCompare();
        foreach (FileInfo file in allfiles)
        {
            int pos = ~files.BinarySearch(file, cmp);
            files.Insert(pos, file);
        }
        Console.WriteLine("Count = {0:#,###}, Read = {1}, Sort = {2}, Memory = {3:#,###}", files.Count, sortStart - start, DateTime.Now - sortStart, GC.GetTotalMemory(false) - memory);
    }

Это вывод вышеуказанной программы:

Count = 16,357, Read = 00:00:03.5793579, Sort = 00:00:06.7776777, Memory = 5,758,976
Count = 16,357, Read = 00:00:03.2173217, Sort = 00:00:06.1616161, Memory = 7,339,920
Count = 16,357, Read = 00:00:03.5083508, Sort = 00:00:06.7556755, Memory = 10,346,504

Это выполняется за 3 секунды, выделяя от 5 до 10 МБ, сканируя 6 931 каталог и возвращая имена файлов по 16 КБ. Это в три раза больше того, о чем вы говорите, и я держу пари, что большую часть времени сканирует дерево каталогов (у меня нет каталога с файлами 5k) Наихудшие затраты всегда будут такими, если вы можете выбрасывать файлы, сопоставляя имена файлов, я бы порекомендовал это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...