【问题标题】:Tree traversal algorithm for directory structures with a lot of files具有大量文件的目录结构的树遍历算法
【发布时间】:2015-09-25 04:40:34
【问题描述】:

当递归遍历目录结构时,如果文件多于目录,使用什么算法最有效?我注意到当使用深度优先遍历时,当给定目录中有很多文件时,它似乎需要更长的时间。在这种情况下,广度优先遍历是否更有效?目前我无法分析这两种算法,因此非常欢迎您提供见解。

编辑:针对 alphazero 的评论,我在 Linux 机器上使用 PHP。

【问题讨论】:

  • 为什么不能分析这两种算法?
  • 致 Zoidberg:实际上,我不知道该怎么做。我刚刚开始重新开始开发,并且正在尝试与我回到大学时所做的相同的事情。但这一次,我想更好地理解事情。知道如何有效地测试吗?
  • 在您指定 (a) 语言/操作系统,(b) 您对文件执行的操作之前,您不会得到任何有意义的答案。此外,“似乎需要更长的时间”听起来也不是事实。从基础开始:在开始之前获取系统时间并在完成后测量增量,以便您/我们知道它是“似乎”还是“确实”。
  • 抱歉含糊其辞。我不能像你希望的那样具体,因为我不知道如何正确地测试这个案例。我正是出于这个原因问这个问题。
  • @oninea 在你的代码中添加一个变量来计算时间,看看遍历一个目录需要多长时间。

标签: algorithm tree-traversal


【解决方案1】:

由于您的文件多于目录,因此看起来您正在处理嵌套非常深的目录,这会使 DFS 比 BFS 占用更多的内存(因此需要更多的时间)。本质上,BFS 和 DFS 都做同样的事情(即访问图表的每个节点),因此通常它们的速度应该不会有任何显着差异。

如果没有实际看到您的实现,很难说出为什么您的 DFS 会变慢。由于文件系统中的链接/快捷方式,您确定不会多次访问相同的节点吗?如果您使用基于显式堆栈的 DFS 而不是递归,您也可能会获得显着的加速。

【讨论】:

    【解决方案2】:

    您可能只想在每个目录中扫描一次目录中的内容,因此processing order - 在访问其他目录之前或之后处理目录的内容可能比您是否进行深度优先更重要或广度优先搜索。根据您的文件系统,与stating 以查看它们是文件还是目录相比,更快而不是更晚地处理文件节点也可能更有效。因此,我建议将预订深度优先搜索作为起点,因为它最容易实现并且最有可能具有良好的缓存/搜索性能。

    总而言之 - 预购深度优先 - 进入目录时,列出其内容,处理该目录中的所有文件,并保存子目录名称列表。然后依次进入每个子目录。只需将程序的调用堆栈用作堆栈,除非您知道自己有非常深的目录结构。

    【讨论】:

      【解决方案3】:

      广度优先会更好地工作是有道理的。当您进入根文件夹时,您会创建一个需要处理的项目列表。其中一些项目是文件,一些是目录。

      如果您使用广度优先,您将处理目录中的文件并忘记它们,然后再转到其中一个子目录。

      如果您使用深度优先,则需要不断增加文件列表,以便稍后在深入挖掘时处理。这将使用更多内存来维护您要处理的文件列表,可能会导致更多页面错误等...

      另外,您无论如何都需要浏览新项目列表,以确定哪些是您可以深入研究的目录。当您开始处理文件时,您需要再次浏览相同的列表(减去目录)。

      【讨论】:

      • “广度优先”搜索的描述是预购深度优先搜索。
      【解决方案4】:

      使用 BFS 遍历目录结构(如 Igor 所述)。

      当你到达一个目录时,启动一个线程来列出目录中的所有文件。

      一旦完成列出/遍历文件,就终止线程。

      因此,每个目录都会有单独的线程来列出文件。

      示例:

      root
      
        - d1
          - d1.1
          - d1.2
          - f1.1 ... f1.100
      
        - d2
          - d2.1
          - d2.2
          - d2.3
          - f2.1 ... f2.200
      
        - d3 
          ....
      

      输出可能看起来像这样 ->

       got d1
      
         started thread to get files of d1
      
         got d2
      
         started thread to get files of d1
      
         done with files in d1
      
         got d3
      
         started thread to get files of d1
      
         got d1.1
         started thread to get files of d1.1
      
         got d1.2
         started thread to get files of d1.2
      

      所以当你回来遍历目录的深处时 获取文件的线程将完成(几乎)它的工作。

      希望这会有所帮助。

      【讨论】:

        【解决方案5】:

        这将是 Windows 中最有效的(类 DirectoryTreeReader),它首先使用呼吸并存储每个目录。

        static const uint64 DIRECTORY_INDICATOR = -1;//std::numeric_limits <uint64>::max();
        
        class DirectoryContent {
        
        public:
            DirectoryContent(const CString& path)
            : mIndex(-1) 
            {
                CFileFind finder;
                finder.FindFile(path + L"\\*.*");
                BOOL keepGoing = FALSE;
                do {
                    keepGoing = finder.FindNextFileW();
                    if (finder.IsDots()) {
                        // Do nothing...
                    } else if (finder.IsDirectory()) {
                        mPaths.push_back(finder.GetFilePath());
                        mSizes.push_back(DIRECTORY_INDICATOR);
                    } else {
                        mPaths.push_back(finder.GetFilePath());
                        mSizes.push_back(finder.GetLength());
                    }
                } while(keepGoing);
            }
        
            bool OutOfRange() const {
                return mIndex >= mPaths.size();
            }
            void Advance() {
                ++mIndex;
            }
            bool IsDirectory() const {
                return mSizes[mIndex] == DIRECTORY_INDICATOR;
            }
            const CString& GetPath() const {
                return mPaths[mIndex];
            }
            uint64 GetSize() const {
                return mSizes[mIndex];
            }
        
        private:
            CStrings mPaths;
            std::vector <uint64> mSizes;
            size_t mIndex;
        };
        
        class DirectoryTreeReader{
            DirectoryTreeReader& operator=(const DirectoryTreeReaderRealtime& other) {};
            DirectoryTreeReader(const DirectoryTreeReaderRealtime& other) {};
        
        public:
            DirectoryTreeReader(const CString& startPath)
            : mStartPath(startPath){
                Reset();
            }
        
            void Reset() {
                // Argh!, no clear() in std::stack
                while(!mDirectoryContents.empty()) {
                    mDirectoryContents.pop(); 
                }
                mDirectoryContents.push( DirectoryContent(mStartPath) );
                Advance();
            }
            void Advance() {
                bool keepGoing = true;
                while(keepGoing) {
                    if (mDirectoryContents.empty()){
                        return;
                    }
                    mDirectoryContents.top().Advance();
                    if (mDirectoryContents.top().OutOfRange()){
                        mDirectoryContents.pop();
                    } else if ( mDirectoryContents.top().IsDirectory() ){
                        mDirectoryContents.push( DirectoryContent(mDirectoryContents.top().GetPath()) );
                    } else {
                        keepGoing = false;
                    }
                }
            }
            bool OutOfRange() const {
                return mDirectoryContents.empty();
            }
            const CString& GetPath() const {
                return mDirectoryContents.top().GetPath();
            }
            uint64 GetSize() const {
                return mDirectoryContents.top().GetSize();
            }
        
        private:
            const CString mStartPath;
            std::stack <DirectoryContent> mDirectoryContents;
        };
        

        【讨论】:

          猜你喜欢
          • 2016-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-02
          • 1970-01-01
          • 1970-01-01
          • 2011-08-29
          • 1970-01-01
          相关资源
          最近更新 更多