c# - 有没有比这更快的方法来查找目录和所有子目录中的所有文件?

标签 c# .net file-io directory

我正在编写一个程序,需要在目录及其所有子目录中搜索具有特定扩展名的文件。这将在本地和网络驱动器上使用,因此性能有点问题。

这是我现在使用的递归方法:

private void GetFileList(string fileSearchPattern, string rootFolderPath, List<FileInfo> files)
{
    DirectoryInfo di = new DirectoryInfo(rootFolderPath);

    FileInfo[] fiArr = di.GetFiles(fileSearchPattern, SearchOption.TopDirectoryOnly);
    files.AddRange(fiArr);

    DirectoryInfo[] diArr = di.GetDirectories();

    foreach (DirectoryInfo info in diArr)
    {
        GetFileList(fileSearchPattern, info.FullName, files);
    }
}

我可以将 SearchOption 设置为 AllDirectories 并且不使用递归方法,但将来我想插入一些代码来通知用户当前正在扫描哪个文件夹。

虽然我正在创建一个 FileInfo 对象列表,但现在我真正关心的是文件的路径。我将有一个现有的文件列表,我想将其与新的文件列表进行比较,以查看添加或删除了哪些文件。有没有更快的方法来生成这个文件路径列表?我可以做些什么来围绕查询共享网络驱动器上的文件来优化此文件搜索?


更新 1

我尝试创建一个非递归方法,该方法通过首先找到所有子目录然后迭代扫描每个目录中的文件来执行相同的操作。方法如下:

public static List<FileInfo> GetFileList(string fileSearchPattern, string rootFolderPath)
{
    DirectoryInfo rootDir = new DirectoryInfo(rootFolderPath);

    List<DirectoryInfo> dirList = new List<DirectoryInfo>(rootDir.GetDirectories("*", SearchOption.AllDirectories));
    dirList.Add(rootDir);

    List<FileInfo> fileList = new List<FileInfo>();

    foreach (DirectoryInfo dir in dirList)
    {
        fileList.AddRange(dir.GetFiles(fileSearchPattern, SearchOption.TopDirectoryOnly));
    }

    return fileList;
}

更新 2

好吧,我已经在本地和远程文件夹上运行了一些测试,这两个文件夹都有很多文件 (~1200)。这是我运行测试的方法。结果如下。

  • GetFileListA():上述更新中的非递归解决方案。我认为这等同于 Jay 的解决方案。
  • GetFileListB():来自原题的递归方法
  • GetFileListC():使用静态Directory.GetDirectories()方法获取所有目录。然后使用静态 Directory.GetFiles() 方法获取所有文件路径。填充并返回一个列表
  • GetFileListD():Marc Gravell 的解决方案使用队列并返回 IEnumberable。我用生成的 IEnumerable 填充了一个列表
    • DirectoryInfo.GetFiles:未创建其他方法。从根文件夹路径实例化 DirectoryInfo。使用 SearchOption.AllDirectories 调用 GetFiles
  • Directory.GetFiles:未创建其他方法。使用 SearchOption.AllDirectories 调用目录的静态 GetFiles 方法
Method                       Local Folder       Remote Folder
GetFileListA()               00:00.0781235      05:22.9000502
GetFileListB()               00:00.0624988      03:43.5425829
GetFileListC()               00:00.0624988      05:19.7282361
GetFileListD()               00:00.0468741      03:38.1208120
DirectoryInfo.GetFiles       00:00.0468741      03:45.4644210
Directory.GetFiles           00:00.0312494      03:48.0737459

. . .so 看起来 Marc 的速度最快。

最佳答案

试试这个避免递归的迭代器 block 版本和 Info 对象:

public static IEnumerable<string> GetFileList(string fileSearchPattern, string rootFolderPath)
{
    Queue<string> pending = new Queue<string>();
    pending.Enqueue(rootFolderPath);
    string[] tmp;
    while (pending.Count > 0)
    {
        rootFolderPath = pending.Dequeue();
        try
        {
            tmp = Directory.GetFiles(rootFolderPath, fileSearchPattern);
        }
        catch (UnauthorizedAccessException)
        {
            continue;
        }
        for (int i = 0; i < tmp.Length; i++)
        {
            yield return tmp[i];
        }
        tmp = Directory.GetDirectories(rootFolderPath);
        for (int i = 0; i < tmp.Length; i++)
        {
            pending.Enqueue(tmp[i]);
        }
    }
}

另请注意,4.0 具有内置的迭代器 block 版本(EnumerateFilesEnumerateFileSystemEntries),它们可能更快(更直接地访问文件系统;数组更少)

关于c# - 有没有比这更快的方法来查找目录和所有子目录中的所有文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2106877/

相关文章:

c# - 如果有意隐藏,请使用 new 关键字

c# - 在 get 中返回值和分配属性有什么区别?

java - OS X 上是否有特定于 Java 的打开文件限制?

windows - 用于删除早于 N 天的文件的批处理文件

c++ - seekg 的第二次调用不起作用

javascript - 突出显示 jQuery 日期选择器中的特定日期

c# - 将泛型 IEnumerable<T> 转换为 IEnumerable<KeyValuePair> (C#)

c# - Entity Framework "SELECT IN"不使用参数

.net - 从 .NET 应用程序拖放到资源管理器

c# - 带 Sympy 的 IronPython 脚本