C# 递归搜索目录中的文件

C# 递归搜索目录中的文件,c#,recursion,C#,Recursion,我有下面的代码通过一个目录递归搜索文件,该目录将所有xml文件的列表返回给我。除了根目录中的xml文件不包括在列表中之外,所有这些都可以正常工作 我理解为什么,因为它做的第一件事是获取根目录中的目录,然后获取文件,因此错过了对根目录的GetFiles()调用。我尝试在foreach之前包含GetFiles()调用,但结果并不像我预期的那样 public static ArrayList DirSearch(string sDir) { try { foreach

我有下面的代码通过一个目录递归搜索文件,该目录将所有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
var extensions = new List<string> { ".txt", ".xml" };
string[] files = Directory.GetFiles(sDir, "*.*", SearchOption.AllDirectories)
                    .Where(f => extensions.IndexOf(Path.GetExtension(f)) >= 0).ToArray();
代码返回:

test2.0.xml
test2.1.xml
test3.0.xml
test3.1.xml
我想返回每个文件,包括:

test1.0.xml
test1.1.xml
test1.2.xml

不太好用递归。任何指针都将不胜感激。

您应该在目录上的循环之前或之后对文件进行循环,但不要像您所做的那样嵌套在其中

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);
}
您可以使用搜索子目录,例如:

string[] files = Directory.GetFiles(sDir, "*.xml", SearchOption.AllDirectories);
这样只能搜索一个扩展,但您可以使用以下内容:

RootDirectory
        test1.0.xml
            test1.1.xml
            test1.2.xml
  2ndLevDir
            test2.0.xml
            test2.1.xml
  3rdLevDir
               test3.0.xml
               test3.1.xml
var extensions = new List<string> { ".txt", ".xml" };
string[] files = Directory.GetFiles(sDir, "*.*", SearchOption.AllDirectories)
                    .Where(f => extensions.IndexOf(Path.GetExtension(f)) >= 0).ToArray();

请参阅文档以了解可能引发的异常,例如,如果代码在没有适当访问权限的帐户下运行,则UnauthorizedAccessException。

请尝试以下方法:

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;
}
公共静态IEnumerable GetXMLFiles(字符串目录)
{
列表文件=新列表();
尝试
{
files.AddRange(Directory.GetFiles(Directory,*.xml),SearchOption.AllDirectories));
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
}
归还文件;
}

这将递归返回所有xml文件:

var allFiles = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);

您需要将文件的循环移动到文件夹的循环之外。此外,您还需要将保存文件集合的数据结构传递给方法的每个调用。这样,所有文件都会进入一个列表

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;
}
公共静态列表目录搜索(字符串sDir,列表文件)
{
foreach(Directory.GetFiles(sDir,*.xml)中的字符串f)
{
字符串扩展名=Path.GetExtension(f);
if(extension!=null&(extension.Equals(.xml)))
{
添加(f);
}
}
foreach(Directory.GetDirectories(sDir)中的字符串d)
{
DirSearch(d,文件);
}
归还文件;
}
那就这样说吧

List<string> files = DirSearch("c:\foo", new List<string>());
List files=DirSearch(“c:\foo”,new List());
更新:


我不知道,直到我读到另一个答案,已经有一个内置的机制来实现这一点。如果您有兴趣了解如何修改代码以使其正常工作,我将留下我的答案。

您正在创建三个列表,而不是使用一个列表(您不使用
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);
  }
}
static void Main(字符串[]args)
{
var list=新列表();
目录搜索(列表“.”);
foreach(列表中的var文件)
{
Console.WriteLine(文件);
}
}
公共静态void目录搜索(列表文件、字符串开始目录)
{
尝试
{
foreach(Directory.GetFiles(startDirectory,*.*)中的字符串文件)
{
字符串扩展名=Path.GetExtension(文件);
if(扩展名!=null)
{
文件。添加(文件);
}
}
foreach(directory.getdirectory(startDirectory)中的字符串目录)
{
目录搜索(文件、目录);
}
}
捕获(System.e例外)
{
控制台写入线(e.Message);
}
}

您可以执行以下操作:

foreach (var file in Directory.GetFiles(MyFolder, "*.xml", SearchOption.AllDirectories))
        {
            // do something with this file
        }

使用EnumerateFiles获取嵌套目录中的文件。 使用AllDirectory在所有目录中递归

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

对于文件和目录搜索的目的,我想提供使用专门的多线程.NET库,它拥有广泛的搜索机会,工作速度非常快

您可以在GitHub上找到有关库的所有信息:

如果您想下载,可以在以下位置下载:

如果你有任何问题,请问他们

这是一个演示示例,说明了如何使用它:

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
    }
}
类搜索器
{
私有静态对象锁定器=新对象();
私有文件搜索器;
列出文件;
公共搜索者()
{
files=new List();//创建将包含搜索结果的列表
}
公共无效Startsearch()
{
CancellationTokenSource tokenSource=新的CancellationTokenSource();
//创建tokenSource以获取停止搜索过程的可能性
searcher=newfilesearcher(@“C:\”,(f)=>
{
返回Regex.IsMatch(f.Name,@“*[Dd]ragon.*.jpg$”;
},tokenSource);//在构造函数中指定tokenSource
searcher.FilesFound+=(发件人,参数)=>//订阅FilesFound事件
{
锁(储物柜)//使用锁是强制性的
{
arg.Files.ForEach((f)=>
{
files.Add(f);//将下一个收到的文件添加到搜索结果列表中
WriteLine($“文件位置:{f.FullName},\n创建时间:{f.CreationTime}”);
});
如果(files.Count>=10)//可以选择任何停止条件
searcher.StopSearch();
}
};
searcher.SearchCompleted+=(发件人,arg)=>//订阅SearchCompleted事件
{
if(arg.IsCanceled)//检查是否调用了StopSearch()
控制台.WriteLine(“搜索已停止”);
其他的
Console.WriteLine(“搜索已完成”);
Console.WriteLine($“文件数量:{files.Count}”);//显示查找文件的数量
};
startsearchsync();
//将搜索进程作为一个异步操作启动,该操作不会阻止被调用的线程
}
}

我尝试了这里列出的一些其他解决方案,但在单元测试期间,代码会抛出我想忽略的异常。我最终创建了以下递归搜索方法,该方法将忽略某些异常,如PathToolOngA异常