System.IO.Directory.GetFiles için birden çok dosya uzantısı searchPattern


140

Ayarlamak için sözdizimi nedir çoklu dosya uzantıları olarak searchPatternüzerinde Directory.GetFiles()? Örneğin, .aspx ve .ascx uzantılı dosyaları filtreleme .

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

Güncelleme : LINQ bir seçenek değildir , bu bir olmak zorunda searchPatterngeçirilen GetFilessöz konusu belirtildiği gibi,.


Bence hiç yok. Tüm dosyaları listeleyin ve ardından el ile filtreleyin veya birden çok araştırıcıda birleştirme yapın. Ama eminim SO ile ilgili bu soruyu daha önce görmüştüm.
CodesInChaos


Daha önce sordu ve burada cevap verdi: stackoverflow.com/questions/163162/…
David

Yanıtlar:


41

Ben "kutunun dışında" bir çözüm olduğuna inanıyorum, bu Directory.GetFiles yönteminin bir sınırlamasıdır.

Yine de kendi yönteminizi yazmak oldukça kolaydır, işte bir örnek .

Kod şöyle olabilir:

/// <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
Bu, her filtre için tüm dizini döngüye alacağınız için bunu yapmanın çok yetersiz bir yoludur. Bunun yerine, filtreye sahip olup olmadığını listelemek için her dosyayı kontrol etmelisiniz. Bu konuda açıklanan yanıtı kullanabilirsiniz: stackoverflow.com/questions/3754118/…
ot0

191
var filteredFiles = Directory
    .GetFiles(path, "*.*")
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Düzenle 2014-07-23

Daha hızlı bir numaralandırma için .NET 4.5'te bunu yapabilirsiniz:

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

MSDN'de Directory.NumerateFiles


5
@Mario Vernari: GetFilesgeri döner string[].
jgauffin

4
* EndsWith () argümanından kaldırmalısınız, joker karakter eşleşmeleri yapmaz.
Hans Passant

3
dosyanın uzantılarını karşılaştırırsanız, '.Where (file => new FileInfo (dosya) .Extension.Equals (". aspx") || new FileInfo (dosya) .Extension.Equals (". ascx") gibi tam eşleşmeyi döndürür. ) '
Damith

3
Directory.EnumerateFilesPerformans artışı için yeni .NET4'ü unutmayın ... stackoverflow.com/questions/5669617/…
drzaus

6
Ve her zaman file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);yerine kullanabilirsinizToLower
drzaus

30

GetFiles yalnızca tek bir kalıpla eşleşebilir, ancak GetFiles'i birden çok kalıpla çağırmak için Linq'i kullanabilirsiniz:

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

Buradaki yorumlar bölümüne bakın: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


2
Desenler çakışırsa çarpışırlar. Ör new string[]{"*.txt","filename.*"}. Ancak, DistinctFileInfo nesneleri semantik eşitlik yerine başvuru eşitliğini kullanarak karşılaştırma yaptığından , çağrıyı bu sorunu gerçekten çözmez. Bir Distinctveya kaldırılarak sabitlenebilir IEqualityComparer<FileInfo>. İlkini yapmak için düzenlendi.
Brian

SelectManyAynı dosya yapısı üzerinde tekrar tekrar (ve tekrar) yineleyeceğini düşünüyorum, bu yüzden performans açısından alt-optimal olabilir.
Dejan

28

Ben okunabilir ve dizinin birden çok yinelemeleri önler, çünkü bu yöntemi seviyorum:

var allowedExtensions = new [] {".doc", ".docx", ".pdf", ".ppt", ".pptx", ".xls", ".xslx"}; 
var files = Directory
    .GetFiles(folder)
    .Where(file => allowedExtensions.Any(file.ToLower().EndsWith))
    .ToList();

2
Uzantı dizimi ayrıştırmak ve regex veya diğer manuel çalışma eklemek zorunda değilsiniz çünkü bu çok daha iyi. Teşekkürler!
Ian Newland

@Jodrell, ya da sadece birHashSet<string>
Jodrell

Uzantı için bir dizi yerine HashSet <string> burada anlamsızdır, çünkü uzantı sayısı sınırlıdır ve dizi EndsWith () gerçekleşene kadar her dosya için yinelenir. Yöntemin çok sayıda uzantıda performans için ayarlanması gerekiyorsa, bir Hashset kullanılabilir. Geçerli olması için, her dosyanın uzantısının EndsWith () - yöntemi yerine açıkça eşleştirilmesi (bölünmesi, eşleşmesi) gerekir. Bu, okunabilirliğe zarar verir ve tüm gerçek yaşam kullanım vakaları olmasa bile çoğunda önemli bir faydası olmaz. Bunun için topluluk düzenlemesini geri aldım.
Marc

15

Korkarım böyle bir şey yapmak zorunda kalacaksın, regex'i buradan mutasyona uğrattım .

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

Bu hoş bir yaklaşım gibi görünüyor, eksik kısmı test edilmiş (çalışan) düzenli bir ifadeye sahip
olmaktır

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

Veya globlarınızı bölmek ve birleştirmek daha hızlı olabilir (en azından daha temiz görünüyor):

"*.ext1;*.ext2".Split(';')
    .SelectMany(g => Directory.EnumerateFiles(path, g))
    .ToList();

ve daha ayrıntılı "orijinal" soru üzerine yeniden gönderme - stackoverflow.com/questions/163162/…
drzaus

6

Hatırlaması kolay, tembel ve belki de kusurlu çözüm:

Directory.GetFiles(dir, "*.dll").Union(Directory.GetFiles(dir, "*.exe"))

4

Aşağıdakileri kullanırdım:

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 ve DirectoryInfo arasındaki uyumsuzluk nedeniyle düzeltildi


3

".Aspx" ve ".ascx" uzantılı dosyaları almanın daha etkili bir yolu, dosya sistemini birkaç kez sorgulamayı önleyen ve çok sayıda istenmeyen dosya döndürmeyi önleyen, yaklaşık bir arama deseni kullanarak dosyaları önceden filtrelemek ve sonucu daha sonra daraltmak için:

var filteredFiles = Directory.GetFiles(path, "*.as?x")
    .Select(f => f.ToLowerInvariant())
    .Where(f => f.EndsWith("px") || f.EndsWith("cx"))
    .ToList();

2

Gibi bir şey belirtmeye çalışırdım

var searchPattern = "as?x";

İşe yaramalı.


Hah! Aspx ve ascx'in çok benzer olduğundan ve böyle bir hack çözümü oluşturacağından korktum. Genel bir şey istiyorum.
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 işlevi Path.GetExtension()yerine , yöntemi kullanmayı tercih ediyorum . İşte tam örnek:

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

veya:

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

( StringComparison.OrdinalIgnoreCasePerformansı önemsiyorsanız kullanın : MSDN dizesi karşılaştırmaları )


1

bu demoya benziyor:

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
Sen- Path.GetExtensionebilmek kullanma sen var .
jgauffin

1

@Baniel B, bu fonksiyonun kendi versiyonumu yazma önerisi için teşekkürler. Directory.GetFiles ile aynı davranışa sahiptir, ancak normal ifade filtrelemeyi destekler.

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

Yararlı buldum, bu yüzden paylaşacağımı düşündüm.


1

c @ qfactor77 yanıtının sürümü. Bu LINQ olmadan en iyi yoldur.

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

şimdi filePathdizeyi döndür. Başlangıçta ihtiyacınız var

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

ayrıca referans eklemeniz gerekir Microsoft.VisualBasic


1

İhtiyacınız olan sayıda uzantıyı aramak için basit bir yol yaptım ve 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 üzerinde çalışıyor.


1

Böyle yapabilirsin

new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)

Soru: LINQ bir seçenek değil, bu yüzden bu cevap yararlı değil
Arci

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

Kod için ek açıklama ekleyin. OP'nin cevabınızı daha iyi anlamasına yardımcı olabilir.
user2339071

-2

Sadece FileIO.FileSystem.GetFilesbunun yerine kullanırsanız Directory.GetFiles, bir dizi joker karaktere izin vereceğini söylemek isterim .

Örneğin:

Dim wildcards As String() = {"*.html", "*.zip"}
Dim ListFiles As List(Of String) = FileIO.FileSystem.GetFiles(directoryyouneed, FileIO.SearchOption.SearchTopLevelOnly, wildcards).ToList

Kişi nereden edinir FileIO?
Joel Martinez

1
Visual Studio'da (2015) ortamınıza zaten dahil edilmiş olmalıdır. Microsoft.VisualBasic ad alanının bir parçasıdır. Benim durumumda VisualBasic çünkü bu benim tercih ettiğim dil.
qfactor77
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.