代码之家  ›  专栏  ›  技术社区  ›  Marek

快速(低级)方法递归处理文件夹中的文件

  •  4
  • Marek  · 技术社区  · 15 年前

    我的应用程序索引最终用户计算机上所有硬盘的内容。 我正在使用directory.getfiles和directory.getdirectories递归处理整个文件夹结构。我只为一些选定的文件类型(最多10个文件类型)编制索引。

    我在profiler中看到,大多数索引时间都花在枚举文件和文件夹上,这取决于实际索引的文件的比例高达90%。

    我希望尽可能快地建立索引。我已经优化了索引本身和索引文件的处理。

    我在考虑使用win32 api调用,但实际上我在探查器中看到大部分处理时间实际上都花在了.net所做的这些api调用上。

    是否有一个(可能是低级)方法可以从C访问,使文件/文件夹的枚举至少部分更快?


    按照注释中的要求,我当前的代码(只是修剪了不相关部分的方案):

        private IEnumerable<IndexedEntity> RecurseFolder(string indexedFolder)
        {
            //for a single extension:
            string[] files = Directory.GetFiles(indexedFolder, extensionFilter);
            foreach (string file in files)
            {
                yield return ProcessFile(file);
            }
            foreach (string directory in Directory.GetDirectories(indexedFolder))
            {
                //recursively process all subdirectories
                foreach (var ie in RecurseFolder(directory))
                {
                    yield return ie;
                }
            }
        }
    
    2 回复  |  直到 15 年前
        1
  •  2
  •   Marc Gravell    15 年前

    在.NET 4.0中,有内置的 enumerable file listing methods 因为离这儿不远,我想试试看。如果有大量填充的文件夹(需要大数组分配),这可能是一个特别的因素。

    如果 深度 问题是,我将考虑扁平化您的方法以使用本地堆栈/队列和 单一的 迭代器块。这将减少用于枚举深度文件夹的代码路径:

        private static IEnumerable<string> WalkFiles(string path, string filter)
        {
            var pending = new Queue<string>();
            pending.Enqueue(path);
            string[] tmp;
            while (pending.Count > 0)
            {
                path = pending.Dequeue();
                tmp = Directory.GetFiles(path, filter);
                for(int i = 0 ; i < tmp.Length ; i++) {
                    yield return tmp[i];
                }
                tmp = Directory.GetDirectories(path);
                for (int i = 0; i < tmp.Length; i++) {
                    pending.Enqueue(tmp[i]);
                }
            }
        }
    

    重复一遍,创建 ProcessFile 从结果中。

        2
  •  1
  •   Elemental    15 年前

    如果您认为.NET实现导致了这个问题,那么我建议您使用winapi调用findfirst、findnext等。

    在我看来,.NET需要大量的内存,因为列表被完全复制到每个目录级别的数组中-因此,如果您的目录结构是10个级别的深度,那么您在任何给定时刻都有10个版本的数组文件,并且为结构中的每个目录分配/释放该数组。

    使用相同的递归技术和\findfirst等只需要在每个递归级别上保持目录结构中某个位置的句柄。