System.IO.Directory.GetFiles的多个文件扩展名searchPattern


140

多个文件扩展名设置为searchPatternon 的语法是什么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/…–
David

Answers:


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

MSDN中的Directory.EnumerateFiles


5
@Mario Vernari:GetFiles返回string[]
jgauffin

4
您必须从EndsWith()参数中删除*,它不会进行通配符匹配。
汉斯·帕桑

3
如果比较文件扩展名,它将返回完全匹配的内容,例如'.Where(file => new FileInfo(file).Extension.Equals(“。aspx”)|| new FileInfo(file).Extension.Equals(“。ascx”) )'
Damith

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将再次遍历相同的文件结构,因此就性能而言可能不是最佳的。
Dejan

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
我更喜欢它,因为我不必解析扩展数组并将其添加到正则表达式或其他手动工作中。谢谢!
伊恩·纽兰德2015年

@Jodrell,或者只是HashSet<string>
Jodrell

HashSet <string>而不是扩展名的数组在这里没有意义,因为扩展名的数量是有限的,并且每个文件都会迭代该数组,直到EndsWith()为true。如果需要针对大量扩展对方法进行性能调整,则可以使用哈希集。为了生效,每个文件的扩展名都需要显式地匹配(先拆分,然后匹配),而不是EndsWith()方法。这将损害可读性,并且在大多数(即使不是全部)现实生活用例中也不会有重大意义。为此,我回滚了社区编辑。
马克

15

我担心您将不得不做这样的事情,我从这里修改了正则表达式。

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

这似乎是一种不错的方法,缺少的部分是具有经过测试的(有效的)正则表达式
JuniorMayhé2012年

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

或者,拆分和合并您的glob可能更快(至少看起来更干净):

"*.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();

编辑:更正了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
    /// <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

@ qfactor77答案的C#版本。这是没有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();

为代码添加其他说明。这可能有助于OP更好地理解您的答案。
user2339071 2015年

-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
Joel Martinez

1
它应该已经包含在Visual Studio(2015)中的环境中。它是Microsoft.VisualBasic命名空间的一部分。就我而言,是VisualBasic,因为这是我选择的语言。
qfactor77
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.