代码之家  ›  专栏  ›  技术社区  ›  Jason Z

你能用多个过滤器调用directory.getfiles()吗?

  •  310
  • Jason Z  · 技术社区  · 17 年前

    我正在尝试使用 Directory.GetFiles() 方法来检索多种类型的文件列表,例如 mp3 S和 jpg 我已经尝试了以下两种方法,但都没有成功:

    Directory.GetFiles("C:\\path", "*.mp3|*.jpg", SearchOption.AllDirectories);
    Directory.GetFiles("C:\\path", "*.mp3;*.jpg", SearchOption.AllDirectories);
    

    有一种方法可以在一次通话中做到这一点吗?

    26 回复  |  直到 7 年前
        1
  •  456
  •   Community Mohan Dere    9 年前

    对于.NET 4.0及更高版本,

    var files = Directory.EnumerateFiles("C:\\path", "*.*", SearchOption.AllDirectories)
                .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));
    

    对于早期版本的.NET,

    var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories)
                .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));
    

    编辑: 请阅读评论。改进 Paul Farry 建议,以及内存/性能问题 Christian.K 指出两者都很重要。

        2
  •  52
  •   Albert    14 年前

    这个怎么样?

    private static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
    {
       return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
    }
    

    我在这里(评论中)找到它: http://msdn.microsoft.com/en-us/library/wz42302f.aspx

        3
  •  29
  •   abatishchev Karl Johan    15 年前

    如果要检查的扩展名列表很大,可以使用以下内容。我不想创建很多或语句,所以我修改了Lette写的内容。

    string supportedExtensions = "*.jpg,*.gif,*.png,*.bmp,*.jpe,*.jpeg,*.wmf,*.emf,*.xbm,*.ico,*.eps,*.tif,*.tiff,*.g01,*.g02,*.g03,*.g04,*.g05,*.g06,*.g07,*.g08";
    foreach (string imageFile in Directory.GetFiles(_tempDirectory, "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower())))
    {
        //do work here
    }
    
        4
  •  26
  •   Community Mohan Dere    9 年前

    对于

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

    你可以:

    public IEnumerable<string> FilterFiles(string path, params string[] exts) {
        return
            Directory
            .EnumerateFiles(path, "*.*")
            .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
    }
    

    但真正的好处是 EnumerateFiles 拆分筛选器并合并结果时显示:

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

    如果你不需要把它们变成球状物(即 exts = new[] {"*.mp3", "*.jpg"} 已经)。

    基于以下LinqPad测试的性能评估(注: Perf 重复学员10000次) https://gist.github.com/zaus/7454021

    (从“副本”转发和扩展,因为该问题未明确要求LINQ: Multiple file-extensions searchPattern for System.IO.Directory.GetFiles )

        5
  •  14
  •   Icehunter    13 年前

    我知道这是个老问题,但林肯:(.net40+)

    var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));
    
        6
  •  11
  •   bluish dmajkic    14 年前

    另一种使用LINQ的方法,但不必返回所有内容并在内存中对其进行筛选。

    var files = Directory.GetFiles("C:\\path", "*.mp3", SearchOption.AllDirectories).Union(Directory.GetFiles("C:\\path", "*.jpg", SearchOption.AllDirectories));
    

    实际上有两个电话 GetFiles() 但我认为这与问题的精神是一致的,并以一个可枚举的形式返回它们。

        7
  •  8
  •   Bas1l    13 年前

    还有一种下降解决方案,似乎没有任何内存或性能开销,而且非常优雅:

    string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
    string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
    
        8
  •  7
  •   ChrisLively    17 年前

    不。尝试以下操作:

    List<string> _searchPatternList = new List<string>();
        ...
        List<string> fileList = new List<string>();
        foreach ( string ext in _searchPatternList )
        {
            foreach ( string subFile in Directory.GetFiles( folderName, ext  )
            {
                fileList.Add( subFile );
            }
        }
    
        // Sort alpabetically
        fileList.Sort();
    
        // Add files to the file browser control    
        foreach ( string fileName in fileList )
        {
            ...;
        }
    

    取自: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx

        9
  •  6
  •   abatishchev Karl Johan    14 年前

    var set = new HashSet<string> { ".mp3", ".jpg" };
    

    然后

    Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
             .Where(f => set.Contains(
                 new FileInfo(f).Extension,
                 StringComparer.OrdinalIgnoreCase));
    

    from file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
    from ext in set
    where String.Equals(ext, new FileInfo(file).Extension, StringComparison.OrdinalIgnoreCase)
    select file;
    
        10
  •  5
  •   abatishchev Karl Johan    14 年前

    我不能用 .Where 方法,因为我正在.NET Framework 2.0中编程(Linq仅在.NET Framework 3.5+中受支持)。

    下面的代码不区分大小写(因此 .CaB .cab 也将列出)。

    string[] ext = new string[2] { "*.CAB", "*.MSU" };
    
    foreach (string found in ext)
    {
        string[] extracted = Directory.GetFiles("C:\\test", found, System.IO.SearchOption.AllDirectories);
    
        foreach (string file in extracted)
        {
            Console.WriteLine(file);
        }
    }
    
        11
  •  4
  •   community wiki 2 revs Alexander Popov    16 年前

    以下函数搜索由逗号分隔的多个模式。您还可以指定排除,例如:“!web.config将搜索所有文件并排除“web.config”。图案可以混合。

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

    用途:

    foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
                {
                    Console.WriteLine(file);
                }
    
        12
  •  4
  •   abatishchev Karl Johan    14 年前
    List<string> FileList = new List<string>();
    DirectoryInfo di = new DirectoryInfo("C:\\DirName");
    
    IEnumerable<FileInfo> fileList = di.GetFiles("*.*");
    
    //Create the query
    IEnumerable<FileInfo> fileQuery = from file in fileList
                                      where (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")
                                      orderby file.LastWriteTime
                                      select file;
    
    foreach (System.IO.FileInfo fi in fileQuery)
    {
        fi.Attributes = FileAttributes.Normal;
        FileList.Add(fi.FullName);
    }
    
        13
  •  3
  •   Jason Z    17 年前

    只是找到了另一种方法。仍然不是一个手术,而是把它扔出去看看别人怎么想。

    private void getFiles(string path)
    {
        foreach (string s in Array.FindAll(Directory.GetFiles(path, "*", SearchOption.AllDirectories), predicate_FileMatch))
        {
            Debug.Print(s);
        }
    }
    
    private bool predicate_FileMatch(string fileName)
    {
        if (fileName.EndsWith(".mp3"))
            return true;
        if (fileName.EndsWith(".jpg"))
            return true;
        return false;
    }
    
        14
  •  3
  •   Pankaj    10 年前

    怎么样

    string[] filesPNG = Directory.GetFiles(path, "*.png");
    string[] filesJPG = Directory.GetFiles(path, "*.jpg");
    string[] filesJPEG = Directory.GetFiles(path, "*.jpeg");
    
    int totalArraySizeAll = filesPNG.Length + filesJPG.Length + filesJPEG.Length;
    List<string> filesAll = new List<string>(totalArraySizeAll);
    filesAll.AddRange(filesPNG);
    filesAll.AddRange(filesJPG);
    filesAll.AddRange(filesJPEG);
    
        15
  •  2
  •   Evado    14 年前

    将扩展名设置为一个字符串,即“.mp3.jpg.wma.wmf”,然后检查每个文件是否包含所需的扩展名。 这与.NET 2.0一起工作,因为它不使用Linq。

    string myExtensions=".jpg.mp3";
    
    string[] files=System.IO.Directory.GetFiles("C:\myfolder");
    
    foreach(string file in files)
    {
       if(myExtensions.ToLower().contains(System.IO.Path.GetExtension(s).ToLower()))
       {
          //this file has passed, do something with this file
    
       }
    }
    

    这种方法的优点是,您可以在不编辑代码的情况下添加或删除扩展,即添加PNG图像,只需编写myExtensions=“.jpg.mp3.png”。

        16
  •  2
  •   bluish dmajkic    14 年前
    /// <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();
    }
    
        17
  •  2
  •   bluish dmajkic    14 年前

    NOP…我相信你必须尽可能多地调用你想要的文件类型。

    我将自己创建一个函数,在具有所需扩展名的字符串上获取一个数组,然后在该数组上迭代进行所有必要的调用。该函数将返回与我发送的扩展名匹配的文件的通用列表。

    希望它有帮助。

        18
  •  2
  •   Stefan Steiger Marco van de Voort    11 年前

    在.NET 2.0中(无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()
    }
    

    然后使用它:

    foreach (string fn in GetFilez(path
                                 , System.IO.SearchOption.AllDirectories
                                 , "*.xml", "*.xml.rels", "*.rels"))
    {}
    
        19
  •  2
  •   Pankaj    10 年前
    DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));
    
    //Using Union
    
    FileInfo[] files = directory.GetFiles("*.xlsx")
                                .Union(directory
                                .GetFiles("*.csv"))
                                .ToArray();
    
        20
  •  1
  •   Quispie    13 年前

    我有同样的问题,找不到正确的解决方案,所以我写了一个名为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();
    }
    

    此函数将调用 Directory.Getfiles() 只有一次。

    例如,调用如下函数:

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

    编辑:要获取具有多个扩展名的文件,请使用此文件:

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

    例如,调用如下函数:

    string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");
    
        21
  •  1
  •   Janis    13 年前

    我想知道为什么有这么多的“解决方案”张贴?

    如果我对getfiles如何工作的新手理解是正确的,那么只有两个选项,上面的任何解决方案都可以归结为:

    1. getfiles,然后filter:fast,但是在应用所有过滤器之前,由于存储开销,这是一个内存杀手。

    2. 当getfiles时过滤:设置的过滤器越多,速度越慢,但是由于不存储开销,内存使用率就越低。
      上面的一篇文章用一个令人印象深刻的基准解释了这一点:每个过滤器选项都会导致一个单独的getfile操作,因此硬盘驱动器的同一部分会被多次读取。

    在我看来,选项1)更好,但是在C:\这样的文件夹上使用searchoption.alldirectories会占用大量内存。
    因此,我只需要创建一个递归子方法,使用选项1遍历所有子文件夹)

    这只会导致每个文件夹上只有1个getfiles操作,因此速度很快(选项1),但在每个子文件夹读取之后应用筛选器时,只需使用少量内存->在每个子文件夹之后删除开销。

    如果我错了,请纠正我。正如我所说,我对编程还很陌生,但我想更深入地了解一些事情,最终变得擅长于此:)

        22
  •  0
  •   elle0087    9 年前

    我不知道哪种解决方案更好,但我使用的是:

    String[] ext = "*.ext1|*.ext2".Split('|');
    
                List<String> files = new List<String>();
                foreach (String tmp in ext)
                {
                    files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
                }
    
        23
  •  0
  •   Crusha K. Rool    8 年前

    如果您使用的是vb.net(或将依赖项导入到C项目中),那么实际上存在一个方便的方法,它允许筛选多个扩展名:

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

    在vb.net中,可以通过我的命名空间访问:

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

    不幸的是,这些便利方法不支持一个延迟评估的变量,比如 Directory.EnumerateFiles() 做。

        24
  •  0
  •   WillyS    7 年前

    使用getfiles搜索模式过滤扩展名是不安全的!! 例如,您有两个文件test1.xls和test2.xlsx,您希望使用搜索模式*.xls过滤掉XLS文件,但getfiles同时返回test1.xls和test2.xlsx。 我不知道这一点,当一些临时文件突然被当作正确的文件处理时,在生产环境中出错。搜索模式为*.txt,临时文件名为*.txt20181028 U 100753898 因此,搜索模式不可信,您还必须添加对文件名的额外检查。

        25
  •  -1
  •   Pankaj    10 年前

    或者您可以将扩展字符串转换为字符串^

    vector <string>  extensions = { "*.mp4", "*.avi", "*.flv" };
    for (int i = 0; i < extensions.size(); ++i)
    {
         String^ ext = gcnew String(extensions[i].c_str());;
         String^ path = "C:\\Users\\Eric\\Videos";
         array<String^>^files = Directory::GetFiles(path,ext);
         Console::WriteLine(ext);
         cout << " " << (files->Length) << endl;
    }
    
        26
  •  -2
  •   Hassaan Raza    8 年前

    希望这能帮助别人:

    //getting only playable Audio/Video Files from open dialog
    
    OpenFileDialog dlg = new OpenFileDialog();
    
    dlg.Filter = ""All Media Files|*.wav;*.aac;*.wma;*.wmv;*.avi;*.mpg;*.mpeg;*.m1v;*.mp2;*.mp3;*.mpa;*.mpe;*.m3u;*.mp4;*.mov;*.3g2;*.3gp2;*.3gp;*.3gpp;*.m4a;*.cda;*.aif;*.aifc;*.aiff;*.mid;*.midi;*.rmi;*.mkv;*.WAV;*.AAC;*.WMA;*.WMV;*.AVI;*.MPG;*.MPEG;*.M1V;*.MP2;*.MP3;*.MPA;*.MPE;*.M3U;*.MP4;*.MOV;*.3G2;*.3GP2;*.3GP;*.3GPP;*.M4A;*.CDA;*.AIF;*.AIFC;*.AIFF;*.MID;*.MIDI;*.RMI;*.MKV";
    
    dlg.ShowDialog();