Пошук декількох розширень файлівPattern для 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, як зазначено в питанні.


Я не думаю, що існує. Перелічіть усі файли, а потім фільтруйте вручну або виконайте об'єднання за допомогою декількох пошукових запитів. Але я майже впевнений, що раніше я бачив це точне запитання.
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

190
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


5
@Mario Vernari: GetFilesповертається string[].
jgauffin

4
Ви повинні вилучити * з аргументу EndsWith (), це не відповідає збіговим символам.
Ганс Пасант

3
якщо порівняти розширення файлу, він поверне точну відповідність на зразок '.Where (файл => новий FileInfo (файл) .Extension.Equals (". aspx") || новий FileInfo (файл) .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
Мені це подобається набагато краще, тому що мені не потрібно розбирати свій розширений масив і додавати його в регулярний вимір або іншу ручну роботу. Дякую!
Ян Ньюленд

@Jodrell, або простоHashSet<string>
Jodrell

HashSet <string> замість масиву для розширення тут не має сенсу, оскільки кількість розширень обмежена і масив стає ітераційним для кожного файлу, поки EndsWith () не стане істинним. Якщо метод потрібно налаштувати на ефективність для дуже великої кількості розширень, може бути використаний Hashset. Для того, щоб набути чинності, розширення кожного файлу потрібно буде явно зіставити (розділити, потім збіг) замість методу EndsWith (). Це завдасть шкоди читальності і не матиме значної користі у більшості, якщо не у всіх випадках використання реального життя. Я для цього відмовив редагування спільноти.
Марк

15

Я боюся , що ви повинні зробити Somthing як це, я мутував регулярний вираз з тут .

var searchPattern = new Regex(
    @"$(?<=\.(aspx|ascx))", 
    RegexOptions.IgnoreCase);
var files = Directory.EnumerateFiles(path)
    .Where(f => searchPattern.IsMatch(f))
    .ToList();

це здається приємним підходом, відсутня частина - мати перевірене (робоче) регулярне вираження
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();

і перепроведенні на «оригінальний» питання з більш докладно - 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();

EDIT: виправлено через невідповідність між 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 занадто схожі і дадуть таке хак-рішення, як це. Я хочу чогось загального.
Seb Nilsson

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();
    }

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 )


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()));
}

1
У вас є те, Path.GetExtensionщо ви можете використовувати.
jgauffin

1

@Daniel B, дякую за пропозицію написати власну версію цієї функції. Він має таку ж поведінку, що і 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();
    }

Я вважав це корисним, тому думав, що поділюсь.


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 - це не варіант, тому ця відповідь не корисна
Арчі

0
var filtered = Directory.GetFiles(path)
    .Where(file => file.EndsWith("aspx", StringComparison.InvariantCultureIgnoreCase) || file.EndsWith("ascx", StringComparison.InvariantCultureIgnoreCase))
    .ToList();

Додайте додаткове пояснення до коду. Це може допомогти ОП зрозуміти вашу відповідь краще.
user2339071

-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

Де придбати FileIO?
Джоель Мартінес

1
Він повинен бути вже включений у ваше оточення у Visual Studio (2015). Він є частиною простору імен Microsoft.VisualBasic. У моєму випадку VisualBasic, тому що це моя мова вибору.
qfactor77
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.