开发者

Multiple file-extensions searchPattern for System.IO.Directory.GetFiles

开发者 https://www.devze.com 2023-03-27 11:29 出处:网络
What开发者_如何学JAVA is the syntax for setting multiple file-extensions as searchPattern on Directory.GetFiles()? For example filtering out files with .aspx and .ascx extensions.

What开发者_如何学JAVA is the syntax for setting multiple file-extensions as searchPattern on Directory.GetFiles()? For example filtering out files with .aspx and .ascx extensions.

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

Update: LINQ is not an option, it has to be a searchPattern passed into GetFiles, as specified in the question.


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

Edit 2014-07-23

You can do this in .NET 4.5 for a faster enumeration:

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

Directory.EnumerateFiles in MSDN


I like this method, because it is readable and avoids multiple iterations of the directory:

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


I believe there is no "out of the box" solution, that's a limitation of the Directory.GetFiles method.

It's fairly easy to write your own method though, here is an example.

The code could be:

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


GetFiles can only match a single pattern, but you can use Linq to invoke GetFiles with multiple patterns:

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

See comments section here: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


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();
  • Don't forget the new .NET4 Directory.EnumerateFiles for a performance boost (What is the difference between Directory.EnumerateFiles vs Directory.GetFiles?)
  • "IgnoreCase" should be faster than "ToLower"

Or, it may be faster to split and merge your globs (at least it looks cleaner):

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


I fear you will have to do somthing like this, I mutated the regex from here.

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


The easy-to-remember, lazy and perhaps imperfect solution:

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


I would use the following:

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: corrected due mismatch between Directory and DirectoryInfo


I would try to specify something like

var searchPattern = "as?x";

it should work.


A more efficient way of getting files with the extensions ".aspx" and ".ascx" that avoids querying the file system several times and avoids returning a lot of undesired files, is to pre-filter the files by using an approximate search pattern and to refine the result afterwards:

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


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


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


Instead of the EndsWith function, I would choose to use the Path.GetExtension() method instead. Here is the full example:

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

or:

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

(Use StringComparison.OrdinalIgnoreCase if you care about performance: MSDN string comparisons)


You can do it like this

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


look like this demo:

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


@Daniel B, thanks for the suggestion to write my own version of this function. It has the same behavior as Directory.GetFiles, but supports regex filtering.

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

I found it useful, so I thought I'd share.


c# version of @qfactor77's answer. This is the best way without 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);

now return filePath string array. In the beginning you need

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

also you need to add reference to Microsoft.VisualBasic


I did a simple way for seach as many extensions as you need, and with no 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();

Working on .Net Standard 2.0.


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


Just would like to say that if you use FileIO.FileSystem.GetFiles instead of Directory.GetFiles, it will allow an array of wildcards.

For example:

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


(Sorry to write this as an answer, but I don't have privileges to write comments yet.)

Note that the FileIO.FileSystem.GetFiles() method from Microsoft.VisualBasic is just a wrapper to execute a search for each provided pattern and merge the results. When checking the source from the .pbd file, you can see from this fragment FileSystem.FindPaths is executed for each pattern in the collection:

private static void FindFilesOrDirectories(
  FileSystem.FileOrDirectory FileOrDirectory,
  string directory,
  SearchOption searchType,
  string[] wildcards,
  Collection<string> Results)
{
    // (...)
    string[] strArray = wildcards;
    int index = 0;
    while (index < strArray.Length)
    {
      string wildCard = strArray[index];
      FileSystem.AddToStringCollection(Results, FileSystem.FindPaths(FileOrDirectory, directory, wildCard));
      checked { ++index; }
    }
    // (...)
}


According to jonathan's answer (for 2 file extensions):

public static string[] GetFilesList(string dir) =>
    Directory.GetFiles(dir, "*.exe", SearchOption.AllDirectories)
    .Union(Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories)).ToArray();
    

Or for more file extensions (search in this folder and subfolders):

public static List<string> GetFilesList(string dir, params string[] fileExtensions) {
    List<string> files = new List<string>();
    foreach (string fileExtension in fileExtensions) {
        files.AddRange(Directory.GetFiles(dir, fileExtension, SearchOption.AllDirectories));
    }
    return files;
}

List<string> files = GetFilesList("C:\\", "*.exe", "*.dll");

In 3250 files took to find 1890 files takes 0.6 second.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号