递归遍历目录树并列出文件名

10

我正在尝试遍历整个目录树并将所有文件名打印在列表框控件上。我写了一些代码,但出现了错误。不确定我做错了什么。顺便说一句,这是在使用Visual Studio中的WPF的C#中。

这是Visual Studio中整个项目解决方案:http://tinyurl.com/a2r5jv9

如果您不想下载项目解决方案,则可在MainWindow.xaml.cs中找到代码:http://pastebin.com/cWRTeq3N

我也会在这里粘贴代码。

public partial class MainWindow : Window
{
    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        string sourcePath = @"C:\temp\";            

        static void DirSearch(string sourcePath)
        {
            try
            {
                foreach (string d in Directory.GetDirectories(sourcePath))
                {
                    foreach (string f in Directory.GetFiles(d))
                    {
                        listBox1.Items.Add(f);
                    }
                    DirSearch(d);
                }
            }                      
            catch (Exception ex)
            {
                listBox1.Items.Add(ex.Message);
            }
        }
    }
}

2
一个方法里面可以包含另一个方法吗? - I4V
1
您的代码示例中似乎有一个拼写错误。 - Ian R. O'Brien
1
具体是哪些错误? - p.s.w.g
1
http://www2.picturepush.com/photo/a/12423735/1024/Anonymous/WpfApplication2---Microsoft-Visual-Studio-%28Adminis.jpg - Steve Way
3个回答

23

在Microsoft支持网站上有一个完整的示例

问题在于你想从事件处理程序中调用DirSearch,但是似乎你正在尝试在事件处理程序内部定义该方法DirSearch。这是无效的。

你需要按照以下方式更改你的代码:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    string sourcePath = @"C:\temp\";
    this.DirSearch(sourcePath);
}

private void DirSearch(string sDir) 
{
    try 
    {
        foreach (string f in Directory.GetFiles(sDir, txtFile.Text)) 
        {
            lstFilesFound.Items.Add(f);
        }

        foreach (string d in Directory.GetDirectories(sDir)) 
        {
            this.DirSearch(d);
        }
    }
    catch (System.Exception excpt)
    {
        listBox1.Items.Add(ex.Message);
    }
}

1
顺便提一下,如何检查重复文件?例如,如果在两个不同的目录中有两个具有相同文件名的文件,则我只想输出一个文件名。 - Steve Way
1
@SteveWay 使用 if (lstFilesFound.Items.Contains(f)) { ... } - p.s.w.g

19

使用接受SearchOption的GetDirectories()重载函数:(参见文档)

string[] dirs = Directory.GetDirectories(path, "*", SearchOption.AllDirectories))
foreach(dir)
{
    ...
}

或者更好的使用`EnumerateFiles()`方法:(链接)
IEnumerable<string> files = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
foreach(files)
{
    ...
}

注意,它执行的是惰性文件系统扫描。


1
这是我在大学作业中的要求。要求使用递归算法。 - Steve Way
4
递归方法还有另一个好处。您可以在文件级别处理异常,而使用“SearchOption.AllDirectories”将会抛出异常,无法继续执行下一个文件/目录(记录日志后)。 - Tim Schmelter
1
如果你需要急切获取文件而不是懒惰,可以使用Directory.GetFiles(带有SearchOption的重载 - 用于递归)。几年前我曾经需要这个功能,当时在Mono中存在一个bug,使用EnumerateFiles时会忽略某些文件,但在GetFiles中却能返回。 - Tomasz Gandor

0

使用引用参数似乎也很有效。尚未针对性能进行基准测试,但这是我目前的解决方案。

public IEnumerable<FileInfo> GetFilesRecursive(string path)
{
    static void GetFiles(DirectoryInfo dir, ref List<FileInfo> files)
    {
        files.AddRange(dir.GetFiles().OrderBy(f => f.Name).ToList());
        foreach (var subdir in dir.GetDirectories())
        {
            GetFiles(subdir, ref files);
        }
    }

    if (!Directory.Exists(path)) return Array.Empty<FileInfo>();
    try
    {
        List<FileInfo> files = new();
        var directory = new DirectoryInfo(path);
        GetFiles(directory, ref files);
        return files;
    }
    catch (Exception e)
    {
        throw new Exception($"Couldn't read files from directory: {path}\n", e);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接