395

我正在尝试使用该Directory.GetFiles()方法来检索多种类型的文件列表,例如mp3's 和jpg's。我尝试了以下两种方法,但都没有运气:

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

有没有办法在一个电话中做到这一点?

4

26 回答 26

587

对于 .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指出的内存/性能问题都非常重要。

于 2008-10-02T16:09:11.927 回答
67

这个怎么样:

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

于 2011-12-11T19:55:28.967 回答
36

如果您有大量的扩展要检查,您可以使用以下内容。我不想创建很多 OR 语句,所以我修改了 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
}
于 2011-01-06T16:36:58.490 回答
34

为了

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

如果您不必将它们变成 glob(即exts = new[] {"*.mp3", "*.jpg"}已经),它会变得更快一些。

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

(从“重复”重新发布和扩展,因为该问题特别要求没有 LINQ:System.IO.Directory.GetFiles 的多个文件扩展搜索模式

于 2013-11-13T18:39:15.773 回答
18

我知道这是老问题,但 LINQ:(.NET40+)

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));
于 2012-10-17T04:18:10.573 回答
15

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

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
于 2013-03-22T13:03:58.223 回答
12

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

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

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

于 2011-12-02T22:31:33.177 回答
8

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;
于 2010-09-14T08:16:22.763 回答
7

没有。尝试以下操作:

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

于 2008-10-02T16:06:20.263 回答
5

我不能使用.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);
    }
}
于 2011-11-26T17:02:46.113 回答
4

以下函数搜索多个模式,以逗号分隔。您还可以指定排除项,例如:“!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);
            }
于 2010-05-31T17:43:28.413 回答
4
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);
}
于 2010-09-18T04:37:25.643 回答
4
DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));

//Using Union

FileInfo[] files = directory.GetFiles("*.xlsx")
                            .Union(directory
                            .GetFiles("*.csv"))
                            .ToArray();
于 2013-04-19T09:40:18.050 回答
4

在 .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"))
{}
于 2014-09-03T11:31:49.337 回答
3

刚刚找到了另一种方法来做到这一点。仍然不是一项操作,而是将其扔出去,看看其他人对此有何看法。

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;
}
于 2008-10-02T17:17:32.183 回答
3

关于什么

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);
于 2015-05-21T18:10:02.457 回答
3

如果您使用的是 VB.NET(或将依赖项导入到 C# 项目中),则实际上存在一种允许过滤多个扩展的便捷方法:

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

在 VB.NET 中,这可以通过 My-namespace 访问:

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

不幸的是,这些方便的方法不支持像这样的延迟评估的变体Directory.EnumerateFiles()

于 2018-02-15T10:36:37.260 回答
2

不...我相信您必须根据所需的文件类型拨打尽可能多的电话。

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

希望能帮助到你。

于 2008-10-02T16:09:01.380 回答
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();
}
于 2011-12-15T07:27:34.730 回答
2

将您想要的扩展名设为一个字符串,即“.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"。

于 2012-04-02T22:24:40.257 回答
2

我想知道为什么发布了这么多“解决方案”?

如果我对 GetFiles 工作原理的菜鸟理解是正确的,那么只有两个选项,上面的任何解决方案都可以归结为这些:

  1. GetFiles,然后过滤:快速,但由于在应用过滤器之前存储开销而成为内存杀手

  2. GetFiles 时过滤:设置的过滤器越多越慢,但内存使用率低,因为没有存储开销。
    这在上面的一篇文章中有一个令人印象深刻的基准进行了解释:每个过滤器选项都会导致单独的 GetFile 操作,因此硬盘驱动器的同一部分会被读取多次。

在我看来,选项 1) 更好,但在 C:\ 之类的文件夹上使用 SearchOption.AllDirectories 会占用大量内存。
因此,我将使用选项 1 制作一个遍历所有子文件夹的递归子方法)

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

如果我错了,请纠正我。正如我所说的那样,我对编程很陌生,但希望对事物有更深入的了解,最终变得擅长这一点:)

于 2013-04-02T15:32:10.607 回答
2

这是获取过滤文件的一种简单而优雅的方法

var allowedFileExtensions = ".csv,.txt";


var files = Directory.EnumerateFiles(@"C:\MyFolder", "*.*", SearchOption.TopDirectoryOnly)
                .Where(s => allowedFileExtensions.IndexOf(Path.GetExtension(s)) > -1).ToArray(); 
于 2020-06-12T10:50:12.070 回答
1

我遇到了同样的问题,找不到正确的解决方案,所以我编写了一个名为 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");
于 2012-12-05T08:39:34.537 回答
0

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

String[] ext = "*.ext1|*.ext2".Split('|');

            List<String> files = new List<String>();
            foreach (String tmp in ext)
            {
                files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
            }
于 2017-07-10T12:47:49.673 回答
0

使用 GetFiles 搜索模式过滤扩展是不安全的!例如,您有两个文件 Test1.xls 和 Test2.xlsx,并且您想使用搜索模式 *.xls 过滤掉 xls 文件,但 GetFiles 同时返回 Test1.xls 和 Test2.xlsx 我不知道这一点并在生产中出错一些临时文件突然被当作正确文件处理的环境。搜索模式是 *.txt 并且临时文件被命名为 *.txt20181028_100753898 所以搜索模式不能被信任,你还必须对文件名添加额外的检查。

于 2018-11-06T11:34:50.173 回答
-1

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

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;
}
于 2014-04-08T20:51:01.680 回答