Можете ли вы вызвать Directory.GetFiles () с несколькими фильтрами? - PullRequest
320 голосов
/ 02 октября 2008

Я пытаюсь использовать метод Directory.GetFiles() для получения списка файлов нескольких типов, таких как mp3 и jpg. Я попробовал оба из следующих безуспешно:

Directory.GetFiles("C:\\path", "*.mp3|*.jpg", SearchOption.AllDirectories);
Directory.GetFiles("C:\\path", "*.mp3;*.jpg", SearchOption.AllDirectories);

Есть ли способ сделать это за один звонок?

Ответы [ 26 ]

473 голосов
/ 02 октября 2008

Для .NET 4.0 и более поздних версий,

var files = Directory.EnumerateFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

Для более ранних версий .NET,

var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

изменить: Пожалуйста, прочитайте комментарии. Улучшение, которое Пол Фарри предлагает, и проблема с памятью / производительностью, на которую указывает Christian.K , очень важны.

52 голосов
/ 11 декабря 2011

Как насчет этого:

private static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
{
   return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
}

Я нашел это здесь (в комментариях): http://msdn.microsoft.com/en-us/library/wz42302f.aspx

29 голосов
/ 06 января 2011

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

string supportedExtensions = "*.jpg,*.gif,*.png,*.bmp,*.jpe,*.jpeg,*.wmf,*.emf,*.xbm,*.ico,*.eps,*.tif,*.tiff,*.g01,*.g02,*.g03,*.g04,*.g05,*.g06,*.g07,*.g08";
foreach (string imageFile in Directory.GetFiles(_tempDirectory, "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower())))
{
    //do work here
}
27 голосов
/ 13 ноября 2013

для

var exts = new[] { "mp3", "jpg" };

Вы могли бы:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return
        Directory
        .EnumerateFiles(path, "*.*")
        .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
}

Но реальное преимущество EnumerateFiles проявляется, когда вы разделяете фильтры и объединяете результаты:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return 
        exts.Select(x => "*." + x) // turn into globs
        .SelectMany(x => 
            Directory.EnumerateFiles(path, x)
            );
}

Это становится немного быстрее, если вам не нужно превращать их в шарики (т.е. уже exts = new[] {"*.mp3", "*.jpg"}).

Оценка производительности на основе следующего теста LinqPad (примечание: Perf просто повторяет делегата 10000 раз) https://gist.github.com/zaus/7454021

(размещено и расширено от «дубликата», поскольку этот вопрос специально не запрашивал LINQ: Несколько файловых расширений searchPattern для System.IO.Directory.GetFiles )

15 голосов
/ 17 октября 2012

Я знаю, что это старый вопрос, но LINQ: (.NET40 +)

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));
11 голосов
/ 03 декабря 2011

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

var files = Directory.GetFiles("C:\\path", "*.mp3", SearchOption.AllDirectories).Union(Directory.GetFiles("C:\\path", "*.jpg", SearchOption.AllDirectories));

На самом деле это 2 звонка на GetFiles(), но я думаю, что это соответствует духу вопроса и возвращает их в одном перечислении.

10 голосов
/ 22 марта 2013

Существует также решение для спуска, которое, похоже, не имеет какой-либо нагрузки на память или производительность и довольно элегантно:

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
7 голосов
/ 02 октября 2008

Неа. Попробуйте следующее:

List<string> _searchPatternList = new List<string>();
    ...
    List<string> fileList = new List<string>();
    foreach ( string ext in _searchPatternList )
    {
        foreach ( string subFile in Directory.GetFiles( folderName, ext  )
        {
            fileList.Add( subFile );
        }
    }

    // Sort alpabetically
    fileList.Sort();

    // Add files to the file browser control    
    foreach ( string fileName in fileList )
    {
        ...;
    }

Взято из: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx

6 голосов
/ 14 сентября 2010

Пусть

var set = new HashSet<string> { ".mp3", ".jpg" };

Тогда

Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
         .Where(f => set.Contains(
             new FileInfo(f).Extension,
             StringComparer.OrdinalIgnoreCase));

или

from file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
from ext in set
where String.Equals(ext, new FileInfo(file).Extension, StringComparison.OrdinalIgnoreCase)
select file;
5 голосов
/ 26 ноября 2011

Я не могу использовать метод .Where, потому что я программирую на .NET Framework 2.0 (Linq поддерживается только в .NET Framework 3.5+).

Приведенный ниже код не чувствителен к регистру (поэтому .CaB или .cab также будут перечислены).

string[] ext = new string[2] { "*.CAB", "*.MSU" };

foreach (string found in ext)
{
    string[] extracted = Directory.GetFiles("C:\\test", found, System.IO.SearchOption.AllDirectories);

    foreach (string file in extracted)
    {
        Console.WriteLine(file);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...