Can you call Directory.GetFiles() with multiple filters?

前端 未结 26 2433
逝去的感伤
逝去的感伤 2020-11-22 05:25

I am trying to use the Directory.GetFiles() method to retrieve a list of files of multiple types, such as mp3\'s and jpg\'s. I have t

相关标签:
26条回答
  • 2020-11-22 06:08

    I had the same problem and couldn't find the right solution so I wrote a function called GetFiles:

    /// <summary>
    /// Get all files with a specific extension
    /// </summary>
    /// <param name="extensionsToCompare">string list of all the extensions</param>
    /// <param name="Location">string of the location</param>
    /// <returns>array of all the files with the specific extensions</returns>
    public string[] GetFiles(List<string> extensionsToCompare, string Location)
    {
        List<string> files = new List<string>();
        foreach (string file in Directory.GetFiles(Location))
        {
            if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file);
        }
        files.Sort();
        return files.ToArray();
    }
    

    This function will call Directory.Getfiles() only one time.

    For example call the function like this:

    string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder");
    

    EDIT: To get one file with multiple extensions use this one:

    /// <summary>
        /// Get the file with a specific name and extension
        /// </summary>
        /// <param name="filename">the name of the file to find</param>
        /// <param name="extensionsToCompare">string list of all the extensions</param>
        /// <param name="Location">string of the location</param>
        /// <returns>file with the requested filename</returns>
        public string GetFile( string filename, List<string> extensionsToCompare, string Location)
        {
            foreach (string file in Directory.GetFiles(Location))
            {
                if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.') + 1).ToLower()) &&& file.Substring(Location.Length + 1, (file.IndexOf('.') - (Location.Length + 1))).ToLower() == filename) 
                    return file;
            }
            return "";
        }
    

    For example call the function like this:

    string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");
    
    0 讨论(0)
  • 2020-11-22 06:09

    If you are using VB.NET (or imported the dependency into your C# project), there actually exists a convenience method that allows to filter for multiple extensions:

    Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"});
    

    In VB.NET this can be accessed through the My-namespace:

    My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"})
    

    Unfortunately, these convenience methods don't support a lazily evaluated variant like Directory.EnumerateFiles() does.

    0 讨论(0)
  • 2020-11-22 06:10

    for

    var exts = new[] { "mp3", "jpg" };
    

    You could:

    public IEnumerable<string> FilterFiles(string path, params string[] exts) {
        return
            Directory
            .EnumerateFiles(path, "*.*")
            .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
    }
    
    • 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" (.EndsWith("aspx", StringComparison.OrdinalIgnoreCase) rather than .ToLower().EndsWith("aspx"))

    But the real benefit of EnumerateFiles shows up when you split up the filters and merge the results:

    public IEnumerable<string> FilterFiles(string path, params string[] exts) {
        return 
            exts.Select(x => "*." + x) // turn into globs
            .SelectMany(x => 
                Directory.EnumerateFiles(path, x)
                );
    }
    

    It gets a bit faster if you don't have to turn them into globs (i.e. exts = new[] {"*.mp3", "*.jpg"} already).

    Performance evaluation based on the following LinqPad test (note: Perf just repeats the delegate 10000 times) https://gist.github.com/zaus/7454021

    ( reposted and extended from 'duplicate' since that question specifically requested no LINQ: Multiple file-extensions searchPattern for System.IO.Directory.GetFiles )

    0 讨论(0)
  • 2020-11-22 06:10

    in .NET 2.0 (no Linq):

    public static List<string> GetFilez(string path, System.IO.SearchOption opt,  params string[] patterns)
    {
        List<string> filez = new List<string>();
        foreach (string pattern in patterns)
        {
            filez.AddRange(
                System.IO.Directory.GetFiles(path, pattern, opt)
            );
        }
    
    
        // filez.Sort(); // Optional
        return filez; // Optional: .ToArray()
    }
    

    Then use it:

    foreach (string fn in GetFilez(path
                                 , System.IO.SearchOption.AllDirectories
                                 , "*.xml", "*.xml.rels", "*.rels"))
    {}
    
    0 讨论(0)
  • 2020-11-22 06:11

    There is also a descent solution which seems not to have any memory or performance overhead and be quite elegant:

    string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
    string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
    
    0 讨论(0)
  • 2020-11-22 06:11

    The following function searches on multiple patterns, separated by commas. You can also specify an exclusion, eg: "!web.config" will search for all files and exclude "web.config". Patterns can be mixed.

    private string[] FindFiles(string directory, string filters, SearchOption searchOption)
    {
        if (!Directory.Exists(directory)) return new string[] { };
    
        var include = (from filter in filters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrEmpty(filter.Trim()) select filter.Trim());
        var exclude = (from filter in include where filter.Contains(@"!") select filter);
    
        include = include.Except(exclude);
    
        if (include.Count() == 0) include = new string[] { "*" };
    
        var rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace("!", "").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
        Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));
    
        List<Thread> workers = new List<Thread>();
        List<string> files = new List<string>();
    
        foreach (string filter in include)
        {
            Thread worker = new Thread(
                new ThreadStart(
                    delegate
                    {
                        string[] allfiles = Directory.GetFiles(directory, filter, searchOption);
                        if (exclude.Count() > 0)
                        {
                            lock (files)
                                files.AddRange(allfiles.Where(p => !regex.Match(p).Success));
                        }
                        else
                        {
                            lock (files)
                                files.AddRange(allfiles);
                        }
                    }
                ));
    
            workers.Add(worker);
    
            worker.Start();
        }
    
        foreach (Thread worker in workers)
        {
            worker.Join();
        }
    
        return files.ToArray();
    
    }
    

    Usage:

    foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
                {
                    Console.WriteLine(file);
                }
    
    0 讨论(0)
提交回复
热议问题