你能用多个过滤器调用Directory.GetFiles()吗?

我试图使用Directory.GetFiles()方法检索多种类型的文件列表,如mp3的和jpg的。以下两种方法我都试过了,但都没有成功:

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

有没有办法一次就能搞定?

481557 次浏览

没有。试试下面的方法:

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

Nop……我相信你必须拨打尽可能多的你想要的文件类型。

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

希望能有所帮助。

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

只是找到了另一种方法。仍然不是一次操作,而是把它扔出去,看看其他人是怎么想的。

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

下面的函数搜索多个以逗号分隔的模式。你也可以指定一个排除,例如:"!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);
}

var set = new HashSet<string>(
new[] { ".mp3", ".jpg" },
StringComparer.OrdinalIgnoreCase); // ignore case
var dir = new DirectoryInfo(path);

然后

dir.EnumerateFiles("*.*", SearchOption.AllDirectories)
.Where(f => set.Contains(f.Extension));

from file in dir.EnumerateFiles("*.*", SearchOption.AllDirectories)
from ext in set // makes sense only if it's just IEnumerable<string> or similar
where String.Equals(ext, file.Extension, StringComparison.OrdinalIgnoreCase)
select file;
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);
}

如果你有一个很大的扩展列表要检查,你可以使用下面的。我不想创建很多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
}

我不能使用.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);
}
}

另一种使用Linq的方式,但是不需要返回所有内容并在内存中过滤。

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

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

这个怎么样:

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

/// <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();
}
让你想要的扩展名为一个字符串,即“.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"。

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

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));

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

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

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();

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

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

  1. GetFiles,然后是filter:速度很快,但在应用过滤器之前,由于存储开销,是内存杀手

  2. 在GetFiles时过滤:设置的过滤器越多,速度越慢,但由于没有存储开销,内存使用量就越低。这在上面的一篇文章中解释了一个令人印象深刻的基准:每个过滤器选项都会导致一个单独的GetFile-operation,所以硬盘的同一部分会被读取几次

在我看来,选项1)更好,但使用SearchOption。像C:\这样的文件夹中的所有目录将使用大量内存 因此,我将使用选项1)

创建一个遍历所有子文件夹的递归子方法

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

如果我说错了,请指正。就像我说的,我对编程很陌生,但我想对事情有更深入的了解,最终在这方面做得很好:)

DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));


//Using Union


FileInfo[] files = directory.GetFiles("*.xlsx")
.Union(directory
.GetFiles("*.csv"))
.ToArray();

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 < / p >

(从'duplicate'重新发布和扩展,因为这个问题特别要求没有LINQ: 多个文件扩展searchPattern for System.IO.Directory。getfile < / >)

或者你可以直接将扩展名字符串转换为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;
}

在。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"))
{}

是什么

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

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

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


List<String> files = new List<String>();
foreach (String tmp in ext)
{
files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
}

如果你使用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()那样的惰性求值变量。

使用GetFiles搜索模式来过滤扩展是不安全的!! 例如,你有两个文件Test1.xls和Test2.xlsx,你想用搜索模式*.xls过滤掉xls文件,但是GetFiles同时返回Test1.xls和Test2.xlsx 我没有意识到这一点,当一些临时文件突然被处理为正确的文件时,在生产环境中出现了错误。搜索模式为*.txt,临时文件名为*.txt20181028_100753898 所以搜索模式不能被信任,你必须增加额外的检查文件名以及

下面是一种获得过滤文件的简单而优雅的方法

var allowedFileExtensions = ".csv,.txt";




var files = Directory.EnumerateFiles(@"C:\MyFolder", "*.*", SearchOption.TopDirectoryOnly)
.Where(s => allowedFileExtensions.IndexOf(Path.GetExtension(s)) > -1).ToArray();

您可以将此添加到项目中

public static class Collectables {
public static List<System.IO.FileInfo> FilesViaPattern(this System.IO.DirectoryInfo fldr, string pattern) {
var filter = pattern.Split(" ");
return fldr.GetFiles( "*.*", System.IO.SearchOption.AllDirectories)
.Where(l => filter.Any(k => l.Name.EndsWith(k))).ToList();
}
}

然后像这样在任何地方使用它

new System.IO.DirectoryInfo("c:\\test").FilesViaPattern("txt doc any.extension");