Несколько расширений файла searchPattern для System.IO.Directory.GetFiles

140

Что такое синтаксис для установки нескольких файлов-расширений , как searchPatternна Directory.GetFiles()? Например, отфильтровывать файлы с расширениями .aspx и .ascx .

// TODO: Set the string 'searchPattern' to only get files with
// the extension '.aspx' and '.ascx'.
var filteredFiles = Directory.GetFiles(path, searchPattern);

Обновление : LINQ не является опцией , его необходимо searchPatternпередать GetFiles, как указано в вопросе.

Себ Нильссон
источник
Я не думаю, что есть. Либо перечислите все файлы, а затем отфильтруйте вручную или выполните объединение для нескольких поисковиков. Но я почти уверен, что видел этот точный вопрос на SO раньше.
CodesInChaos
Ранее задавали вопросы и отвечали здесь: stackoverflow.com/questions/163162/…
Дэвид

Ответы:

41

Я считаю, что не существует готового решения, это ограничение метода Directory.GetFiles.

Хотя написать собственный метод довольно легко, вот пример .

Код может быть:

/// <summary>
/// Returns file names from given folder that comply to given filters
/// </summary>
/// <param name="SourceFolder">Folder with files to retrieve</param>
/// <param name="Filter">Multiple file filters separated by | character</param>
/// <param name="searchOption">File.IO.SearchOption, 
/// could be AllDirectories or TopDirectoryOnly</param>
/// <returns>Array of FileInfo objects that presents collection of file names that 
/// meet given filter</returns>
public string[] getFiles(string SourceFolder, string Filter, 
 System.IO.SearchOption searchOption)
{
 // ArrayList will hold all file names
ArrayList alFiles = new ArrayList();

 // Create an array of filter string
 string[] MultipleFilters = Filter.Split('|');

 // for each filter find mathing file names
 foreach (string FileFilter in MultipleFilters)
 {
  // add found file names to array list
  alFiles.AddRange(Directory.GetFiles(SourceFolder, FileFilter, searchOption));
 }

 // returns string array of relevant file names
 return (string[])alFiles.ToArray(typeof(string));
}
Даниэль Б
источник
7
Это очень недостаточный способ сделать это, так как вы будете зацикливать весь каталог для каждого фильтра. Вместо этого вы должны проверить для каждого файла, имеет ли он фильтр, а затем добавить, чтобы сделать список. Вы можете использовать ответ, объясненный в этой теме: stackoverflow.com/questions/3754118/…
ot0
191
var filteredFiles = Directory
    .GetFiles(path, "*.*")
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Редактировать 2014-07-23

Вы можете сделать это в .NET 4.5 для более быстрого перечисления:

var filteredFiles = Directory
    .EnumerateFiles(path) //<--- .NET 4.5
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Directory.EnumerateFiles в MSDN

jgauffin
источник
5
@Mario Vernari: GetFilesвозвращается string[].
jgauffin
4
Вы должны удалить * из аргумента EndsWith (), он не выполняет подстановочные совпадения.
Ганс Пассант
3
если сравнить расширения файла, он вернет точное совпадение как '.Where (file => new FileInfo (file) .Extension.Equals (". aspx") || new FileInfo (file) .Extension.Equals (". ascx") ) '
Дамит
3
Не забудьте новый .NET4 Directory.EnumerateFilesдля повышения производительности ... stackoverflow.com/questions/5669617/…
drzaus
6
И вы всегда можете использовать, file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);а неToLower
drzaus
30

GetFiles может соответствовать только одному шаблону, но вы можете использовать Linq для вызова GetFiles с несколькими шаблонами:

FileInfo[] fi = new string[]{"*.txt","*.doc"}
    .SelectMany(i => di.GetFiles(i, SearchOption.AllDirectories))
    .ToArray();

Смотрите раздел комментариев здесь: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx

Ульрик Магнуссон
источник
2
Они столкнутся, если шаблоны перекрываются. Например, new string[]{"*.txt","filename.*"}. Тем не менее, вызов Distinctфактически не решает эту проблему, поскольку объекты FileInfo сравниваются с использованием ссылочного равенства, а не семантического равенства. Это можно исправить, удалив Distinctили передав его IEqualityComparer<FileInfo>. Отредактировано, чтобы сделать первое.
Брайан
Я думаю, что это SelectManyбудет повторять ту же файловую структуру снова (и снова), так что это может быть неоптимальным с точки зрения производительности.
Деян
28

Мне нравится этот метод, потому что он читабелен и позволяет избежать нескольких итераций каталога:

var allowedExtensions = new [] {".doc", ".docx", ".pdf", ".ppt", ".pptx", ".xls", ".xslx"}; 
var files = Directory
    .GetFiles(folder)
    .Where(file => allowedExtensions.Any(file.ToLower().EndsWith))
    .ToList();
Марк
источник
2
Мне это нравится намного лучше, потому что мне не нужно анализировать массив расширений и добавлять его в регулярные выражения или другую ручную работу. Спасибо!
Ян Ньюленд,
@ Джодрелл, или простоHashSet<string>
Джодрелл
HashSet <string> вместо массива для расширения здесь не имеет смысла, так как количество расширений ограничено, и массив повторяется для каждого файла, пока EndsWith () не станет истинным. Если метод должен быть настроен на производительность для очень большого числа расширений, можно использовать Hashset. Для того чтобы расширение вступило в силу, расширение каждого файла должно было бы совпадать явно (split, затем match) вместо метода EndsWith (). Это повредит читабельности и будет бесполезным в большинстве, если не во всех реальных случаях использования. Я для этого откатил правку сообщества.
Марк
15

Боюсь, тебе придется сделать что-то подобное, я мутировал здесь .

var searchPattern = new Regex(
    @"$(?<=\.(aspx|ascx))", 
    RegexOptions.IgnoreCase);
var files = Directory.EnumerateFiles(path)
    .Where(f => searchPattern.IsMatch(f))
    .ToList();
Jodrell
источник
это кажется хорошим подходом, отсутствующая часть должна иметь проверенное (работающее) регулярное выражение
Junior Mayhé
14
var filteredFiles = Directory
    .EnumerateFiles(path, "*.*") // .NET4 better than `GetFiles`
    .Where(
        // ignorecase faster than tolower...
        file => file.ToLower().EndsWith("aspx")
        || file.EndsWith("ascx", StringComparison.OrdinalIgnoreCase))
    .ToList();

Или это может быть быстрее разделить и объединить ваши шары (по крайней мере, это выглядит чище):

"*.ext1;*.ext2".Split(';')
    .SelectMany(g => Directory.EnumerateFiles(path, g))
    .ToList();
drzaus
источник
и перепост на «оригинальный» вопрос с более подробной информацией - stackoverflow.com/questions/163162/…
drzaus
6

Легко запоминающееся, ленивое и, возможно, несовершенное решение:

Directory.GetFiles(dir, "*.dll").Union(Directory.GetFiles(dir, "*.exe"))
Джонатан
источник
4

Я бы использовал следующее:

var ext = new string[] { ".ASPX", ".ASCX" };
FileInfo[] collection = (from fi in new DirectoryInfo(path).GetFiles()
                         where ext.Contains(fi.Extension.ToUpper())
                         select fi)
                         .ToArray();

РЕДАКТИРОВАТЬ: исправлено из-за несоответствия между Directory и DirectoryInfo

Марио Вернари
источник
3

Более эффективный способ получения файлов с расширениями ".aspx" и ".ascx", который позволяет избежать запросов файловой системы несколько раз и избежать возврата большого количества нежелательных файлов, состоит в предварительной фильтрации файлов с использованием приблизительного шаблона поиска и чтобы уточнить результат впоследствии:

var filteredFiles = Directory.GetFiles(path, "*.as?x")
    .Select(f => f.ToLowerInvariant())
    .Where(f => f.EndsWith("px") || f.EndsWith("cx"))
    .ToList();
Оливье Жако-Дескомб
источник
2

Я бы попробовал указать что-то вроде

var searchPattern = "as?x";

он должен работать.

Давиде Пирас
источник
Хах! Я боялся, что aspx и ascx слишком похожи и приведут к такому решению для взлома. Я хочу что-то общее.
Себ Нильссон
2
    /// <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();
    }
A.Ramazani
источник
2
    public static bool CheckFiles(string pathA, string pathB)
    {
        string[] extantionFormat = new string[] { ".war", ".pkg" };
        return CheckFiles(pathA, pathB, extantionFormat);
    }
    public static bool CheckFiles(string pathA, string pathB, string[] extantionFormat)
    {
        System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo(pathA);
        System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo(pathB);
        // Take a snapshot of the file system. list1/2 will contain only WAR or PKG 
        // files
        // fileInfosA will contain all of files under path directories 
        FileInfo[] fileInfosA = dir1.GetFiles("*.*", 
                              System.IO.SearchOption.AllDirectories);
        // list will contain all of files that have ..extantion[]  
        // Run on all extantion in extantion array and compare them by lower case to 
        // the file item extantion ...
        List<System.IO.FileInfo> list1 = (from extItem in extantionFormat
                                          from fileItem in fileInfosA
                                          where extItem.ToLower().Equals 
                                          (fileItem.Extension.ToLower())
                                          select fileItem).ToList();
        // Take a snapshot of the file system. list1/2 will contain only WAR or  
        // PKG files
        // fileInfosA will contain all of files under path directories 
        FileInfo[] fileInfosB = dir2.GetFiles("*.*", 
                                       System.IO.SearchOption.AllDirectories);
        // list will contain all of files that have ..extantion[]  
        // Run on all extantion in extantion array and compare them by lower case to 
        // the file item extantion ...
        List<System.IO.FileInfo> list2 = (from extItem in extantionFormat
                                          from fileItem in fileInfosB
                                          where extItem.ToLower().Equals            
                                          (fileItem.Extension.ToLower())
                                          select fileItem).ToList();
        FileCompare myFileCompare = new FileCompare();
        // This query determines whether the two folders contain 
        // identical file lists, based on the custom file comparer 
        // that is defined in the FileCompare class. 
        return list1.SequenceEqual(list2, myFileCompare);
    }
Йосси Голдберг
источник
2

Вместо функции EndsWith я бы выбрал Path.GetExtension()вместо этого метод. Вот полный пример:

var filteredFiles = Directory.EnumerateFiles( path )
.Where(
    file => Path.GetExtension(file).Equals( ".aspx", StringComparison.OrdinalIgnoreCase ) ||
            Path.GetExtension(file).Equals( ".ascx", StringComparison.OrdinalIgnoreCase ) );

или:

var filteredFiles = Directory.EnumerateFiles(path)
.Where(
    file => string.Equals( Path.GetExtension(file), ".aspx", StringComparison.OrdinalIgnoreCase ) ||
            string.Equals( Path.GetExtension(file), ".ascx", StringComparison.OrdinalIgnoreCase ) );

(Используйте, StringComparison.OrdinalIgnoreCaseесли вы заботитесь о производительности: сравнение строк MSDN )

BigChief
источник
1

похож на это демо:

void Main()
{
    foreach(var f in GetFilesToProcess("c:\\", new[] {".xml", ".txt"}))
        Debug.WriteLine(f);
}
private static IEnumerable<string> GetFilesToProcess(string path, IEnumerable<string> extensions)
{
   return Directory.GetFiles(path, "*.*")
       .Where(f => extensions.Contains(Path.GetExtension(f).ToLower()));
}
Gildor
источник
1
У вас есть то, Path.GetExtensionчто вы можете использовать.
JGauffin
1

@ Дэниел Б, спасибо за предложение написать мою собственную версию этой функции. Он имеет то же поведение, что и Directory.GetFiles, но поддерживает фильтрацию регулярных выражений.

string[] FindFiles(FolderBrowserDialog dialog, string pattern)
    {
        Regex regex = new Regex(pattern);

        List<string> files = new List<string>();
        var files=Directory.GetFiles(dialog.SelectedPath);
        for(int i = 0; i < files.Count(); i++)
        {
            bool found = regex.IsMatch(files[i]);
            if(found)
            {
                files.Add(files[i]);
            }
        }

        return files.ToArray();
    }

Я нашел это полезным, поэтому я решил поделиться.

Artorias2718
источник
1

c # версия ответа @ qfactor77. Это лучший способ без LINQ.

string[] wildcards= {"*.mp4", "*.jpg"};
ReadOnlyCollection<string> filePathCollection = FileSystem.GetFiles(dirPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, wildcards);
string[] filePath=new string[filePathCollection.Count];
filePathCollection.CopyTo(filePath,0);

теперь возвращаем filePathстроковый массив. В начале вам нужно

using Microsoft.VisualBasic.FileIO;
using System.Collections.ObjectModel;

также вам нужно добавить ссылку на Microsoft.VisualBasic

Риджул Судхир
источник
1

Я сделал простой способ для поиска столько расширений, сколько вам нужно, и без ToLower (), RegEx, foreach ...

List<String> myExtensions = new List<String>() { ".aspx", ".ascx", ".cs" }; // You can add as many extensions as you want.
DirectoryInfo myFolder = new DirectoryInfo(@"C:\FolderFoo");
SearchOption option = SearchOption.TopDirectoryOnly; // Use SearchOption.AllDirectories for seach in all subfolders.
List<FileInfo> myFiles = myFolder.EnumerateFiles("*.*", option)
    .Where(file => myExtensions
    .Any(e => String.Compare(file.Extension, e, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase) == 0))
    .ToList();

Работаем на .Net Standard 2.0.

Карлос Дэвид Лопес
источник
1

Вы можете сделать это так

new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)
гигабайт
источник
В вопросе: LINQ не вариант, поэтому этот ответ не является полезным
Arci
0
var filtered = Directory.GetFiles(path)
    .Where(file => file.EndsWith("aspx", StringComparison.InvariantCultureIgnoreCase) || file.EndsWith("ascx", StringComparison.InvariantCultureIgnoreCase))
    .ToList();
Римский
источник
Добавить дополнительное объяснение для кода. Это может помочь ОП лучше понять ваш ответ.
user2339071 9.09.15
-2

Просто хотел бы сказать, что если вы используете FileIO.FileSystem.GetFilesвместо Directory.GetFiles, это позволит массив подстановочных знаков.

Например:

Dim wildcards As String() = {"*.html", "*.zip"}
Dim ListFiles As List(Of String) = FileIO.FileSystem.GetFiles(directoryyouneed, FileIO.SearchOption.SearchTopLevelOnly, wildcards).ToList
qfactor77
источник
Где можно приобрести FileIO?
Джоэл Мартинес
1
Он должен быть уже включен в вашу среду в Visual Studio (2015). Он является частью пространства имен Microsoft.VisualBasic. В моем случае это VisualBasic, потому что это мой язык по выбору.
qfactor77