如何使用'Directory.getFiles'获取特定扩展名的磁盘上的所有文件并将它们保存在列表中?

4

我正在进行一个控制台项目,其目标是在整个磁盘上搜索扩展名为“.config”的所有文件。

我尝试过以下方式:

foreach (string file in Directory.GetFiles("C:\\", "*.config", SearchOption.AllDirectories))
  {
   Console.WriteLine(file);
   Console.ReadLine();
}

但是出现了“拒绝访问路径(...)”的错误。

在互联网上,我找到了这段代码:

Stack<string> pending = new Stack<string>();
        pending.Push("C:\\");

        while (pending.Count != 0)
        {
            var path = pending.Pop();
            string[] next = null;

            try
            {
                next = Directory.GetFiles(path, "*.config");
            }
            catch { }

            if (next != null && next.Length != 0)
                foreach (var file in next)
                {
                    Console.WriteLine(file);
                    Console.ReadLine();
                }
            try
            {
                next = Directory.GetDirectories(path);
                foreach (var subdir in next) pending.Push(subdir);
            }
            catch { }
        }

但它只会在“回车”键上单击显示路径,我想将这些文件/路径保存在列表中。有人可以帮忙吗?

这是一个很好的起点:https://learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree - EylM
但它只是显示了路径,总是在“enter”上单击。这是因为您在其中有这行代码:Console.ReadLine();。将此行替换为myList.Add(file),然后您应该就完成了。如果您写:“将它们保存在列表中”,那么您至少应该有一个列表来保存它们;) - Mong Zhu
离题:你真的应该避免空的catch子句。将错误消息发送到虚无中并不能帮助你理解出了什么问题。 - Mong Zhu
你需要进行更多的错误捕捉。如果你的foreach子目录被拒绝访问,那么在此之后它将不会再执行任何子目录,这是一个常见的递归代码片段,我们中的许多人都做过类似的事情。 - BugFinder
@BugFinder:Directory.GetDirectories 只有在父目录访问被禁止时才应该抛出 UnauthorizedAccessException 异常。foreach 子目录只是遍历一堆字符串而不访问该字符串的目录/文件,因此不应该抛出异常。 - Chillersanim
显示剩余2条评论
3个回答

1

替换这些行

Console.WriteLine(file);
Console.ReadLine();

使用一种方法将它们存储在列表中。
例如

foundFiles.Add(file);

然后,当方法完成时,您可以从此列表中读取所有找到的文件路径。
注: 这不会产生与过滤器匹配的系统上的所有文件。 只有应用程序可以访问其各自目录的文件才能以这种方式找到。 例如,Windows目录和其他用户的用户目录通常受到保护。(假设您在Windows上运行)
请记住,某些文件可能独立于其目录受到保护。 因此,在尝试读取它们时,也要考虑读取可能失败的事实。 只需使用try catch包围读取即可。

谢谢你的笔记 :) 我尝试添加到列表中,但当我尝试在控制台上显示此列表时,控制台是干净的,什么也不显示。 - Catarina

1

有两件事情可以做来改进这段代码:

  1. 使用 Directory.EnumerateFiles()Directory.EnumerateDirectories() 来避免在每个目录中复制所有文件名。
  2. 将方法的返回类型设置为 IEnumerable<string>,以使其更易于使用。

我们还需要非常小心地处理尝试访问受保护文件和目录引起的异常。下面的代码也因为不允许在 try/catch 块内部使用 yield return 而变得复杂,因此我们必须重新排列代码。

(还要注意,我们必须释放从 .GetEnumerator() 返回的枚举器;通常当您使用 foreach 时,这会自动完成,但在这种情况下我们不能 - 因为必须避免在 try/catch 中进行 yield return - 因此我们必须使用 using 进行处理。)

以下是修改后的原始代码:

public static IEnumerable<string> GetFiles(string root, string spec)
{
    var pending = new Stack<string>(new []{root});

    while (pending.Count > 0)
    {
        var path = pending.Pop();
        IEnumerator<string> fileIterator = null;

        try
        {
            fileIterator = Directory.EnumerateFiles(path, spec).GetEnumerator();
        }

        catch {}

        if (fileIterator != null)
        {
            using (fileIterator)
            {
                while (true)
                {
                    try
                    {
                        if (!fileIterator.MoveNext()) // Throws if file is not accessible.
                            break;
                    }

                    catch { break; }

                    yield return fileIterator.Current;
                }
            }
        }

        IEnumerator<string> dirIterator = null;

        try
        {
            dirIterator = Directory.EnumerateDirectories(path).GetEnumerator();
        }

        catch {}

        if (dirIterator != null)
        {
            using (dirIterator)
            {
                while (true)
                {
                    try
                    {
                        if (!dirIterator.MoveNext()) // Throws if directory is not accessible.
                            break;
                    }

                    catch { break; }

                    pending.Push(dirIterator.Current);
                }
            }
        }
    }
}

作为一个例子,以下是使用控制台应用程序列出在 "C:\" 驱动器上所有可访问的 ".txt" 文件的方法:
static void Main()
{
    foreach (var file in GetFiles("C:\\", "*.txt"))
    {
        Console.WriteLine(file);
    }
}

"root" 是什么意思? - Catarina
@CatarinaBatista root 是你想要开始查找文件的根目录 - 因此,“C:\”表示在 C:\ 及其子目录中的所有文件,而“C:\Windows”表示在“C:\Windows”及其子目录中的所有文件。 - Matthew Watson
@Catarina 如果我们想在整个硬盘上进行剪切怎么办?比如在所有驱动器中查找所有带有 .txt 扩展名的文件。 - Iman Estiri
@ImanS3 也许你需要检查一下磁盘的“标识”,可能是D:\,然后将GetFiles("C:\\", "*.txt")更改为GetFiles("D:\\", "*.txt")。你试过了吗? - Catarina

0
关于错误“拒绝访问路径(...)”,有时您必须以管理员身份运行Visual Studio才能访问C:\驱动器中的某些文件夹。

1
是的,我也尝试以管理员身份运行,但对我无效。 - Catarina

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