我有以下代码通过目录递归搜索文件,该目录返回所有xml文件的列表给我。一切都运行良好,但根目录中的xml文件不包含在列表中。
我理解为什么,因为它首先要做的是获取根目录中的目录,然后获取文件,从而错过了根目录上的GetFiles()调用。我尝试在foreach之前包含GetFiles()调用,但结果并不像我预期的那样。
public static ArrayList DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, "*.xml"))
{
string extension = Path.GetExtension(f);
if (extension != null && (extension.Equals(".xml")))
{
fileList.Add(f);
}
}
DirSearch(d);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return fileList;
}
我的目录结构类似于:
RootDirectory
test1.0.xml
test1.1.xml
test1.2.xml
2ndLevDir
test2.0.xml
test2.1.xml
3rdLevDir
test3.0.xml
test3.1.xml
代码返回:
test2.0.xml
test2.1.xml
test3.0.xml
test3.1.xml
我想返回包含以下内容的所有文件:
test1.0.xml
test1.1.xml
test1.2.xml
不太适用于递归。任何指针都将非常感激。
答案 0 :(得分:93)
您可以使用this overload of Directory.GetFiles搜索子目录,例如:
string[] files = Directory.GetFiles(sDir, "*.xml", SearchOption.AllDirectories);
只能搜索一个扩展程序,但您可以使用以下内容:
var extensions = new List<string> { ".txt", ".xml" };
string[] files = Directory.GetFiles(sDir, "*.*", SearchOption.AllDirectories)
.Where(f => extensions.IndexOf(Path.GetExtension(f)) >= 0).ToArray();
选择具有所需扩展名的文件(对扩展名区分大小写的N.B.)。
在某些情况下,可能需要使用Directory.EnumerateFiles Method:
枚举文件foreach(string f in Directory.EnumerateFiles(sDir, "*.xml", SearchOption.AllDirectories))
{
// do something
}
请参阅文档以了解可能引发的异常,例如,如果代码在没有适当访问权限的帐户下运行,则为UnauthorizedAccessException。
答案 1 :(得分:49)
以递归方式返回所有xml文件:
var allFiles = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
答案 2 :(得分:3)
你应该在循环遍历目录之前或之后循环遍历文件,但不要像你一样嵌套在文件中。
foreach (string f in Directory.GetFiles(d, "*.xml"))
{
string extension = Path.GetExtension(f);
if (extension != null && (extension.Equals(".xml")))
{
fileList.Add(f);
}
}
foreach (string d in Directory.GetDirectories(sDir))
{
DirSearch(d);
}
答案 3 :(得分:3)
尝试以下方法:
public static IEnumerable<string> GetXMLFiles(string directory)
{
List<string> files = new List<string>();
try
{
files.AddRange(Directory.GetFiles(directory, "*.xml", SearchOption.AllDirectories));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return files;
}
答案 4 :(得分:3)
您正在创建三个列表,而不是使用一个(您不使用DirSearch(d)
的返回值)。您可以使用列表作为参数来保存状态:
static void Main(string[] args)
{
var list = new List<string>();
DirSearch(list, ".");
foreach (var file in list)
{
Console.WriteLine(file);
}
}
public static void DirSearch(List<string> files, string startDirectory)
{
try
{
foreach (string file in Directory.GetFiles(startDirectory, "*.*"))
{
string extension = Path.GetExtension(file);
if (extension != null)
{
files.Add(file);
}
}
foreach (string directory in Directory.GetDirectories(startDirectory))
{
DirSearch(files, directory);
}
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
}
答案 5 :(得分:2)
你可以这样做:
foreach (var file in Directory.GetFiles(MyFolder, "*.xml", SearchOption.AllDirectories))
{
// do something with this file
}
答案 6 :(得分:1)
您需要为文件夹的循环外部的文件移动循环。此外,您需要将包含文件集合的数据结构传递给方法的每次调用。这样所有文件都会进入一个列表。
public static List<string> DirSearch(string sDir, List<string> files)
{
foreach (string f in Directory.GetFiles(sDir, "*.xml"))
{
string extension = Path.GetExtension(f);
if (extension != null && (extension.Equals(".xml")))
{
files.Add(f);
}
}
foreach (string d in Directory.GetDirectories(sDir))
{
DirSearch(d, files);
}
return files;
}
然后这样称呼它。
List<string> files = DirSearch("c:\foo", new List<string>());
<强>更新强>
在我不知情的情况下,在我阅读其他答案之前,已经有了内置机制来执行此操作。如果您有兴趣了解如何修改代码以使其正常工作,我将留下我的答案。
答案 7 :(得分:0)
使用EnumerateFiles获取嵌套目录中的文件。 使用AllDirectories来递归目录。
using System;
using System.IO;
class Program
{
static void Main()
{
// Call EnumerateFiles in a foreach-loop.
foreach (string file in Directory.EnumerateFiles(@"c:\files",
"*.xml",
SearchOption.AllDirectories))
{
// Display file path.
Console.WriteLine(file);
}
}
}
答案 8 :(得分:0)
我尝试了此处列出的其他一些解决方案,但是在单元测试期间,代码将引发我想忽略的异常。我最终创建了以下递归搜索方法,该方法将忽略某些异常,例如PathTooLongException和UnauthorizedAccessException。
private IEnumerable<string> RecursiveFileSearch(string path, string pattern, ICollection<string> filePathCollector = null)
{
try
{
filePathCollector = filePathCollector ?? new LinkedList<string>();
var matchingFilePaths = Directory.GetFiles(path, pattern);
foreach(var matchingFile in matchingFilePaths)
{
filePathCollector.Add(matchingFile);
}
var subDirectories = Directory.EnumerateDirectories(path);
foreach (var subDirectory in subDirectories)
{
RecursiveFileSearch(subDirectory, pattern, filePathCollector);
}
return filePathCollector;
}
catch (Exception error)
{
bool isIgnorableError = error is PathTooLongException ||
error is UnauthorizedAccessException;
if (isIgnorableError)
{
return Enumerable.Empty<string>();
}
throw error;
}
}
答案 9 :(得分:-1)
对于文件和目录搜索目的,我希望提供使用专门的多线程.NET库,它具有广泛的搜索机会并且工作速度非常快。
您可以在GitHub上找到有关库的所有信息:https://github.com/VladPVS/FastSearchLibrary
如果您想下载它,可以在此处执行:https://github.com/VladPVS/FastSearchLibrary/releases
如果您有任何疑问,请询问他们。
这是一个如何使用它的示范性示例:
class Searcher
{
private static object locker = new object();
private FileSearcher searcher;
List<FileInfo> files;
public Searcher()
{
files = new List<FileInfo>(); // create list that will contain search result
}
public void Startsearch()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
// create tokenSource to get stop search process possibility
searcher = new FileSearcher(@"C:\", (f) =>
{
return Regex.IsMatch(f.Name, @".*[Dd]ragon.*.jpg$");
}, tokenSource); // give tokenSource in constructor
searcher.FilesFound += (sender, arg) => // subscribe on FilesFound event
{
lock (locker) // using a lock is obligatorily
{
arg.Files.ForEach((f) =>
{
files.Add(f); // add the next received file to the search results list
Console.WriteLine($"File location: {f.FullName}, \nCreation.Time: {f.CreationTime}");
});
if (files.Count >= 10) // one can choose any stopping condition
searcher.StopSearch();
}
};
searcher.SearchCompleted += (sender, arg) => // subscribe on SearchCompleted event
{
if (arg.IsCanceled) // check whether StopSearch() called
Console.WriteLine("Search stopped.");
else
Console.WriteLine("Search completed.");
Console.WriteLine($"Quantity of files: {files.Count}"); // show amount of finding files
};
searcher.StartSearchAsync();
// start search process as an asynchronous operation that doesn't block the called thread
}
}