Можете ли вы вызвать Directory.GetFiles () с несколькими фильтрами?

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

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

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

В качестве примечания: использование шаблона поиска GetFiles для фильтрации расширения небезопасно. Например, у вас есть два файла Test1.xls и Test2.xlsx, и вы хотите отфильтровать файл xls с помощью шаблона поиска * .xls, но GetFiles возвращает оба файла Test1 .xls и Test2.xlsx. Прочтите раздел примечаний для получения дополнительной информации

kiran 07.12.2013 09:54

Так как этого избежать?

Brackets 12.07.2017 22:09

@kiran Как это не безопасно? Это похоже на функцию, а не на ошибку.

Kyle Delaney 15.06.2018 16:05

Так как этого избежать? Использование? .Xls будет правильно фильтровать только файлы xls и, например, не будет включать файлы xlsx.

Dave 28.10.2020 07:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
372
4
414 731
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

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

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

Нет ... Я считаю, что вам нужно делать столько звонков, сколько типов файлов вы хотите.

Я бы сам создал функцию, взяв массив строк с нужными мне расширениями, а затем перебрал бы этот массив, сделав все необходимые вызовы. Эта функция вернет общий список файлов, соответствующих отправленным мной расширениям.

Надеюсь, это поможет.

Ответ принят как подходящий

Для .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, очень важны.

Чувак, мне нужно чаще думать в терминах LINQ. Хорошее решение!

Ken Pespisa 23.09.2009 06:29

Просто убедитесь, что вы понимаете последствия: это вернет файлы все в массиве строк, а затем отфильтрует их по указанным вами расширениям. Это может не быть большой проблемой, если под «C: \ Path» нет большого количества файлов, но может быть проблема с памятью / производительностью на «C: \» или что-то в этом роде.

Christian.K 14.02.2010 15:13

... 2 года спустя: Хороший код, но будьте осторожны, если у вас есть файл с расширением .JPG, он его не сделает. Лучше добавить s.ToLower().Endswith...

Stormenet 05.05.2010 13:35

вы можете просто использовать s.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)

Paul Farry 01.06.2010 02:58

Чтобы сократить условия или, мне нравится делать следующее (хотя я не уверен, что это влияет на производительность больше) ... var files = myDirInfo.GetFiles (). Where (o => new [] { "mp3", "jpg"}. Содержит (o.Extension.ToLower ()). ToArray ();

Matt Winward 26.10.2011 15:39

Обратите внимание, что с .NET 4.0 вы можете заменить Directory.GetFiles на Directory.EnumerateFiles, msdn.microsoft.com/en-us/library/dd383571.aspx, что позволит избежать проблем с памятью, о которых упоминает @ Christian.K.

Jim Mischel 03.12.2011 02:58

@MattWinward вы должны прочитать msdn.microsoft.com/en-us/library/dd465121.aspx

phoog 15.01.2013 10:15

Я сделал некоторые улучшения производительности и предоставил сравнительный код в ответе ниже: stackoverflow.com/questions/163162/…

drzaus 13.11.2013 22:40

@MAC Это параметр лямбда-выражения, в данном случае s представляет каждое имя файла, возвращаемое в результате вызова Directory.EnumerateFiles / Directory.GetFiles.

Christoffer Lette 10.07.2015 14:30

У вас есть решение для .Net 2, пожалуйста?

Fandango68 15.03.2016 04:05

Как проверить, содержит ли имя файла (а не его каталог) конкретную строку?

Christine 13.07.2016 20:46

Если вы хотите еще больше повысить производительность в случае множества возможных расширений, лучше создать HashSet со всеми расширениями и сделать Where(f => _validExtensions.Contains(Path.GetExtension(f).ToLower())). По сути, Contains намного быстрее, чем многократное сравнение строк.

Ilya Chernomordik 21.08.2016 21:19

GetFiles намного быстрее, чем EnumerateFiles

Ashitosh birajdar 29.11.2016 13:23

В контексте данных вам сначала нужны все файлы, а затем вы их фильтруете.

Marek Bar 09.07.2018 14:02

@IlyaChernomordik: Проблема с .Contains в том, что он включает файлы без расширения.

Nick Westgate 10.08.2018 07:37

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

d219 09.07.2020 17:33

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

private void getFiles(string path)
{
    foreach (string s in Array.FindAll(Directory.GetFiles(path, "*", SearchOption.AllDirectories), predicate_FileMatch))
    {
        Debug.Print(s);
    }
}

private bool predicate_FileMatch(string fileName)
{
    if (fileName.EndsWith(".mp3"))
        return true;
    if (fileName.EndsWith(".jpg"))
        return true;
    return false;
}

Следующая функция выполняет поиск по нескольким шаблонам, разделенным запятыми. Вы также можете указать исключение, например: «! Web.config» будет искать все файлы и исключать «web.config». Узоры можно смешивать.

private string[] FindFiles(string directory, string filters, SearchOption searchOption)
{
    if (!Directory.Exists(directory)) return new string[] { };

    var include = (from filter in filters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrEmpty(filter.Trim()) select filter.Trim());
    var exclude = (from filter in include where filter.Contains(@"!") select filter);

    include = include.Except(exclude);

    if (include.Count() == 0) include = new string[] { "*" };

    var rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace("!", "").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
    Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));

    List<Thread> workers = new List<Thread>();
    List<string> files = new List<string>();

    foreach (string filter in include)
    {
        Thread worker = new Thread(
            new ThreadStart(
                delegate
                {
                    string[] allfiles = Directory.GetFiles(directory, filter, searchOption);
                    if (exclude.Count() > 0)
                    {
                        lock (files)
                            files.AddRange(allfiles.Where(p => !regex.Match(p).Success));
                    }
                    else
                    {
                        lock (files)
                            files.AddRange(allfiles);
                    }
                }
            ));

        workers.Add(worker);

        worker.Start();
    }

    foreach (Thread worker in workers)
    {
        worker.Join();
    }

    return files.ToArray();

}

Использование:

foreach (string file in FindFiles(@"D:8.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
            {
                Console.WriteLine(file);
            }

Позволять

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;

У getfiles нет перегрузки u.

nawfal 27.07.2012 17:51

List<string> FileList = new List<string>();
DirectoryInfo di = new DirectoryInfo("C:\DirName");

IEnumerable<FileInfo> fileList = di.GetFiles("*.*");

//Create the query
IEnumerable<FileInfo> fileQuery = from file in fileList
                                  where (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")
                                  orderby file.LastWriteTime
                                  select file;

foreach (System.IO.FileInfo fi in fileQuery)
{
    fi.Attributes = FileAttributes.Normal;
    FileList.Add(fi.FullName);
}

file.Extension.ToLower() - плохая практика.

abatishchev 27.07.2012 18:35

тогда что мы должны использовать? @abatishchev

Nitin S 18.06.2013 14:56

@ Нитин: String.Equals(a, b, StringComparison.OrdinalIgnoreCase)

abatishchev 18.06.2013 21:34

На самом деле, я предпочитаю file.Extension.Equals (". Jpg", StringComparison.OrdinalIgnoreC‌ ase). Вроде бы быстрее, чем .ToLower или .ToUpper, по крайней мере так говорят везде, где я искал. На самом деле .Equals также быстрее, чем ==, поскольку == вызывает .Equals и проверяет наличие null (потому что вы не можете делать null.Equals (null)).

ThunderGr 01.11.2013 17:19

Если у вас есть большой список расширений, которые нужно проверить, вы можете использовать следующее. Я не хотел создавать много операторов ИЛИ, поэтому я изменил то, что написал 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
}

Помогите мне с этим, пожалуйста ... Когда я печатаю imageFile, он дает полный путь к нему. Как я могу сжать его до имени файла.

Naresh 24.05.2011 12:03

System.IO.Path.GetFileName (файл изображения)

jnoreiga 25.05.2011 21:43

Path.GetExtension возвращает ".ext", а не "* .ext" (по крайней мере, в 3.5+).

nullable 05.01.2012 00:43

К вашему сведению: вам нужен System.Linq для .where (

jnoreiga 29.03.2012 01:20

Зачем использовать запятую в качестве разделительного символа? Запрещенный персонаж, такой как | было бы надежнее. Вы бы исключили (редкий) случай, когда расширение содержит запятую в конце.

Ole EH Dufour 21.02.2018 14:08

Есть потенциальный недостаток. Мы давно прошли те времена, когда требуется, чтобы расширения состояли ровно из трех символов. Предположим, вы можете встретить файл с .abc, а supportedExtensions содержит .abcd. Будет совпадать, хотя и не должно. Чтобы исправить: supportedExtensions = ".jpg|.abcd|"; с .Contains(Path.GetExtension(s).ToLower() + "|"). То есть включите в тест свой символ-разделитель. ВАЖНО: ваш символ-разделитель также должен стоять после ПОСЛЕДНЕЙ записи в supportedExceptions.

ToolmakerSteve 02.04.2018 16:10

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

Nick Westgate 10.08.2018 07:32

Я не могу использовать метод .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);
    }
}

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

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

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

Тогда зачем использовать Linq? Будет ли это быстрее, чем использование списка и добавления диапазона?

ThunderGr 01.11.2013 17:16

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

Dave Rael 01.11.2013 21:13

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

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

Я предполагаю, что это позволяет избежать потенциальных ошибок памяти, связанных с ответом с самым высоким рейтингом? В таком случае он должен быть оценен выше!

Dan W 01.02.2013 22:48

@DanW Самый популярный ответ, безусловно, ложится бременем на память, но я думаю, что это не должно быть такой проблемой. Мне тоже понравился этот ответ, но на самом деле он (намного) медленнее, чем принятый ответ. Отметьте это SpeedTest

OttO 14.02.2013 02:37

Спасибо. Приятно видеть, что он всего в два раза медленнее - пока, думаю, я буду придерживаться его.

Dan W 17.02.2013 23:47

Это всего лишь вдвое медленнее, если есть только два расширения. Если у вас есть список X расширений, он будет в X раз медленнее. Потому что здесь вы вызываете функцию Directory.GetFiles несколько раз, тогда как в другом решении она вызывается только один раз.

Oscar Hermosilla 12.05.2016 16:25

@OscarHermosilla Можно использовать Parallel.ForEach, чтобы получить их параллельно

FindOutIslamNow 21.06.2018 15:22

@FindOutIslamNow, но тогда вы ограничены пропускной способностью ввода-вывода

phuclv 31.07.2019 12:24

@OttO плохая ссылка.

Arvo Bowen 10.03.2020 22:58

/// <summary>
/// Returns the names of files in a specified directories that match the specified patterns using LINQ
/// </summary>
/// <param name = "srcDirs">The directories to seach</param>
/// <param name = "searchPatterns">the list of search patterns</param>
/// <param name = "searchOption"></param>
/// <returns>The list of files that match the specified pattern</returns>
public static string[] GetFilesUsingLINQ(string[] srcDirs,
     string[] searchPatterns,
     SearchOption searchOption = SearchOption.AllDirectories)
{
    var r = from dir in srcDirs
            from searchPattern in searchPatterns
            from f in Directory.GetFiles(dir, searchPattern, searchOption)
            select f;

    return r.ToArray();
}

Сделайте нужные расширения одной строкой, например ".mp3.jpg.wma.wmf", а затем проверьте, содержит ли каждый файл нужное вам расширение. Это работает с .net 2.0, поскольку он не использует LINQ.

string myExtensions = ".jpg.mp3";

string[] files=System.IO.Directory.GetFiles("C:\myfolder");

foreach(string file in files)
{
   if (myExtensions.ToLower().contains(System.IO.Path.GetExtension(s).ToLower()))
   {
      //this file has passed, do something with this file

   }
}

Преимущество этого подхода в том, что вы можете добавлять или удалять расширения без редактирования кода, то есть для добавления изображений в формате png просто напишите myExtensions = ". Jpg.mp3.png".

он не знает, что такое s

Brackets 12.07.2017 20:22

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

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));

Хорошая идея. Рассмотрите возможность использования file.ToLower() для упрощения сопоставления расширений в верхнем регистре. И почему бы не извлечь сначала расширение, чтобы Regex не проверял весь путь: Regex.IsMatch(Path.GetExtension(file).ToLower(), @"\.(wav|mp3|txt)");

ToolmakerSteve 02.04.2018 16:17

У меня была такая же проблема, и я не мог найти правильного решения, поэтому я написал функцию GetFiles:

/// <summary>
/// Get all files with a specific extension
/// </summary>
/// <param name = "extensionsToCompare">string list of all the extensions</param>
/// <param name = "Location">string of the location</param>
/// <returns>array of all the files with the specific extensions</returns>
public string[] GetFiles(List<string> extensionsToCompare, string Location)
{
    List<string> files = new List<string>();
    foreach (string file in Directory.GetFiles(Location))
    {
        if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file);
    }
    files.Sort();
    return files.ToArray();
}

Эта функция вызовет Directory.Getfiles() только один раз.

Например, вызовите функцию следующим образом:

string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder");

Обновлено: Чтобы получить один файл с несколькими расширениями, используйте это:

/// <summary>
    /// Get the file with a specific name and extension
    /// </summary>
    /// <param name = "filename">the name of the file to find</param>
    /// <param name = "extensionsToCompare">string list of all the extensions</param>
    /// <param name = "Location">string of the location</param>
    /// <returns>file with the requested filename</returns>
    public string GetFile( string filename, List<string> extensionsToCompare, string Location)
    {
        foreach (string file in Directory.GetFiles(Location))
        {
            if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.') + 1).ToLower()) &&& file.Substring(Location.Length + 1, (file.IndexOf('.') - (Location.Length + 1))).ToLower() == filename) 
                return file;
        }
        return "";
    }

Например, вызовите функцию следующим образом:

string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");

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

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();

Полагаю, я мог бы отредактировать его, чтобы он принимал неизвестное неограниченное количество расширений с новой строковой переменной и функцией разделения. Но даже тогда, чем это лучше, чем решение jnoreiga? Это быстрее? Меньше потребления памяти?

Brackets 12.07.2017 20:33

Есть компромисс. Этот подход вызывает GetFiles несколько раз, по одному на фильтр. Эти множественные вызовы мощь в некоторых ситуациях являются значительными «накладными расходами на производительность». У него есть важное преимущество, заключающееся в том, что каждый GetFiles возвращает только массив с путями к файлам соответствие. Я ожидал, что это как правило будет хорошим результатом по производительности, возможно, даже с производительностью начальство, но это необходимо проверить. Если GetFiles значительно быстрее, чем EnumerateFiles, тогда это может быть лучшим подходом. Также обратите внимание, что последний ".ToArray ()" можно опустить, если IEnumerable можно использовать напрямую.

ToolmakerSteve 02.04.2018 16:32

Интересно, почему опубликовано так много "решений"?

Если мои новички в понимании того, как работает GetFiles, верны, есть только два варианта, и любое из вышеперечисленных решений можно свести к следующему:

  1. GetFiles, затем фильтр: быстро, но убивает память из-за накладных расходов на хранение до применения фильтров

  2. Фильтр во время GetFiles: чем больше фильтров установлено, тем медленнее используется память, так как накладные расходы не сохраняются.
    Это объясняется в одном из вышеупомянутых сообщений с впечатляющим тестом: каждая опция фильтра вызывает отдельную операцию GetFile, поэтому одна и та же часть жесткого диска читается несколько раз.

На мой взгляд, вариант 1) лучше, но использование SearchOption.AllDirectories в таких папках, как C: \, потребует огромных объемов памяти. Поэтому я бы просто сделал рекурсивный под-метод, который проходит через все подпапки, используя вариант 1)

Это должно вызывать только одну операцию GetFiles для каждой папки и, следовательно, быть быстрым (вариант 1), но использовать только небольшой объем памяти, поскольку фильтры применяются после чтения каждой подпапки -> служебные данные удаляются после каждой подпапки.

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

DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));

//Using Union

FileInfo[] files = directory.GetFiles("*.xlsx")
                            .Union(directory
                            .GetFiles("*.csv"))
                            .ToArray();

Как я могу просмотреть files, чтобы узнать путь? Спасибо

Si8 16.12.2020 23:55

для

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

(репост и расширен из 'duplicate', поскольку этот вопрос специально не запрашивал LINQ: Несколько расширений файлов searchPattern для System.IO.Directory.GetFiles)

что вы имеете в виду, говоря «я стану немного быстрее, если вам не нужно превращать их в шары»? Это O (1) или O (n) (в отношении количества файлов, а не количества расширений)? Я бы предположил, что это O (1) (или O (n) в отношении количества расширений) и, вероятно, где-то в диапазоне нескольких циклов процессора ... Если это так, это, вероятно, - с точки зрения производительности - незначительно

BatteryBackupUnit 22.07.2014 16:39

@BatteryBackupUnit да, с 10 тыс. Повторений против 2 расширений разница между glob и str составляет 3 мс, так что да, технически незначительно (см. Ссылку на результаты производительности), но не зная, сколько расширений вам нужно отфильтровать, я решил, что стоит указать, что есть разница; Я оставляю вам решать, лучше ли «упрощенное использование» (например, .FilterFiles(path, "jpg", "gif")), чем «явное использование» (например, .FilterFiles(path, "*.jpg", "*.gif")).

drzaus 23.07.2014 19:42

отлично, спасибо. Извините, я как-то пропустил эту ссылку на github. Может мне стоит изменить настройки цвета экрана :)

BatteryBackupUnit 23.07.2014 22:46

Поддерживает ли это расширение в верхнем регистре, такое как .JPG или .MKV?

Wahyu 23.04.2016 10:18

@Wahyu В моем первом примере вы заметите, что StringComparison.OrdinalIgnoreCase означает, что он будет работать с .jpg, .Jpg или .JPG и т. д.

drzaus 26.04.2016 22:45

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

17 of 26 15.09.2016 16:12

@ 17of26 хороший звонок, спасибо, что указали на это. Забавно, потому что вчера я столкнулся с этим случаем и заметил это только потому, что у меня была куча файлов с «несколькими расширениями» (например, .json.html), которые соответствуют более чем одному глобу.

drzaus 17.09.2016 13:36

@ 17of26 Но я предполагаю / надеюсь, что, поскольку это больше связано с файловой системой с глобусом, он на самом деле не повторяет каждый файл в каталоге, по крайней мере, не в традиционном смысле.

drzaus 17.09.2016 13:41

Есть ловушка с EnumerateFiles, в которой соответствующие трехсимвольные расширения, такие как *.htm, также будут соответствовать *.html или действительно чему-либо, в котором есть .htm (например, .htmfoo). Похоже, это связано со старыми именами файлов DOS 8.3. codeproject.com/Questions/152289/… См. Примечание о searchPattern здесь: docs.microsoft.com/en-us/dotnet/api/…

Michael Haren 25.01.2021 23:58

@MichaelHaren, я не могу воспроизвести это локально в LinqPad 6 или в dotnetfiddle.net/U1zkoI (v4.7.2) - это привязано к определенной версии .NET?

drzaus 09.02.2021 00:04

Или вы можете просто преобразовать строку расширений в String ^

vector <string>  extensions = { "*.mp4", "*.avi", "*.flv" };
for (int i = 0; i < extensions.size(); ++i)
{
     String^ ext = gcnew String(extensions[i].c_str());;
     String^ path = "C:\Users\Eric\Videos";
     array<String^>^files = Directory::GetFiles(path,ext);
     Console::WriteLine(ext);
     cout << " " << (files->Length) << endl;
}

Это C++, а не C#

Brackets 12.07.2017 19:35

в .NET 2.0 (без Linq):

public static List<string> GetFilez(string path, System.IO.SearchOption opt,  params string[] patterns)
{
    List<string> filez = new List<string>();
    foreach (string pattern in patterns)
    {
        filez.AddRange(
            System.IO.Directory.GetFiles(path, pattern, opt)
        );
    }


    // filez.Sort(); // Optional
    return filez; // Optional: .ToArray()
}

Тогда используйте это:

foreach (string fn in GetFilez(path
                             , System.IO.SearchOption.AllDirectories
                             , "*.xml", "*.xml.rels", "*.rels"))
{}

Что о

string[] filesPNG = Directory.GetFiles(path, "*.png");
string[] filesJPG = Directory.GetFiles(path, "*.jpg");
string[] filesJPEG = Directory.GetFiles(path, "*.jpeg");

int totalArraySizeAll = filesPNG.Length + filesJPG.Length + filesJPEG.Length;
List<string> filesAll = new List<string>(totalArraySizeAll);
filesAll.AddRange(filesPNG);
filesAll.AddRange(filesJPG);
filesAll.AddRange(filesJPEG);

Я не знаю, какое решение лучше, но я использую это:

String[] ext = "*.ext1|*.ext2".Split('|');

            List<String> files = new List<String>();
            foreach (String tmp in ext)
            {
                files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
            }

Если вы используете VB.NET (или импортировали зависимость в свой проект C#), на самом деле существует удобный метод, который позволяет фильтровать несколько расширений:

Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"});

В VB.NET к этому можно получить доступ через пространство имен My:

My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"})

К сожалению, эти удобные методы не поддерживают вариант с ленивой оценкой, как Directory.EnumerateFiles().

Это, пожалуй, лучший ответ, но все же принят более хитрый ответ. Должен так любить.

Robbie Coyne 18.11.2019 07:09

Использование шаблона поиска GetFiles для фильтрации расширения небезопасно !! Например, у вас есть два файла Test1.xls и Test2.xlsx, и вы хотите отфильтровать файл xls с помощью шаблона поиска * .xls, но GetFiles возвращает как Test1.xls, так и Test2.xlsx Я не знал об этом и получил ошибку в производственной среде, когда некоторые временные файлы внезапно стали обрабатываться как правильные. Шаблон поиска был * .txt, а временные файлы назывались * .txt20181028_100753898 Таким образом, шаблону поиска нельзя доверять, вам также нужно добавить дополнительную проверку имен файлов.

Не отвечает на вопрос.

Robbie Coyne 18.11.2019 04:50

Вот простой и элегантный способ получить отфильтрованные файлы

var allowedFileExtensions = ".csv,.txt";


var files = Directory.EnumerateFiles(@"C:\MyFolder", "*.*", SearchOption.TopDirectoryOnly)
                .Where(s => allowedFileExtensions.IndexOf(Path.GetExtension(s)) > -1).ToArray(); 

Другие вопросы по теме