簡體   English   中英

C ++中的遞歸列表文件不會進入所有子目錄

[英]Recursive listing files in C++ doesn't enter all subdirectories

!!!解決了!!!

謝謝你們的幫助,現在一切正常。 我按照@RSahu的建議對我的代碼進行了更改並使其正常工作。
感謝您的所有投入,我一直堅持這一點。
致@Basile:我肯定會檢查出來但是對於這段特殊的代碼,我不會用它,因為它看起來太復雜了:)但感謝您的建議。



原始問題

我正在嘗試制作一個C ++代碼來列出給定目錄中的所有文件及其子目錄。

快速解釋

想法是函數list_dirs(_dir, _files, _current_dir)將從頂級目錄開始並將文件放入vector _files ,當它找到目錄時,它將在此目錄上調用自己。 如果在子目錄中, _current_dir將被添加到文件名之前,因為我需要知道路徑結構(它應該生成sitemap.xml)。
list_dirs有一個對list_dir的調用, list_dir返回當前目錄中的所有文件,而不是文件和目錄之間的區別。

我的問題

現在的代碼是,它列出原始目錄中的所有文件,然后列出一個子目錄中的所有文件,但跳過所有其他子目錄。 它會列出它們,但不會列出它們中的文件。
而且更加神秘,它只列出這個特定目錄中的文件而不是其他目錄。 我嘗試在多個位置運行它,但它從未進入任何其他目錄。

在此先感謝,請注意我是C ++初學者,所以不要苛刻;)
LIST_DIR

int list_dir(const std::string& dir, std::vector<std::string>& files){
    DIR *dp;
    struct dirent *dirp;
    unsigned fileCount = 0;

    if ((dp = opendir(dir.c_str())) == NULL){
        std::cout << "Error opening dir." << std::endl;
    }

    while ((dirp = readdir(dp)) != NULL){
        files.push_back(std::string (dirp->d_name));
        fileCount++;
    }

    closedir(dp);
    return fileCount;
}

和LIST_DIRS

int list_dirs (const std::string& _dir, std::vector<std::string>& _files, std::string _current_dir){
    std::vector<std::string> __files_or_dirs;

    list_dir(_dir, __files_or_dirs);

    std::vector<std::string>::iterator it = __files_or_dirs.begin();
    struct stat sb;

    while (it != __files_or_dirs.end()){
        if (lstat((&*it)->c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
            /* how to do this better? */
            if (*it == "." || *it == ".."){
                __files_or_dirs.erase(it);
                continue;
            }

            /* here it should go into sub-directory */
            list_dirs(_dir + *it, _files, _current_dir + *it);

            __files_or_dirs.erase(it);
        } else {
            if (_current_dir.empty()){
                _files.push_back(*it);
            } else {
                _files.push_back(_current_dir + "/" + *it);
            }
            ++it;
        }
    }
}

主要問題在於:

if (lstat((&*it)->c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){

您正在使用lstat調用中的目錄條目的名稱。 當函數處理子目錄時,條目名稱不表示有效路徑。 你需要使用類似的東西:

std::string entry = *it;
std::string full_path = _dir + "/" + entry;
if (lstat(full_path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){

建議改進

更新list_dir ,使其不包含"." 或輸出中的".." 我開始排除這些文件是有道理的。

int list_dir(const std::string& dir, std::vector<std::string>& files){
   DIR *dp;
   struct dirent *dirp;
   unsigned fileCount = 0;

   if ((dp = opendir(dir.c_str())) == NULL){
      std::cout << "Error opening dir." << std::endl;
   }

   while ((dirp = readdir(dp)) != NULL){
      std::string entry = dirp->d_name;
      if ( entry == "." or entry == ".." )
      {
         continue;
      }

      files.push_back(entry);
      fileCount++;
   }

   closedir(dp);
   return fileCount;
}

list_dirs ,不需要從_files_or_dirs刪除項目。 可以使用for循環簡化代碼for並刪除從_files_or_dirs刪除項目的調用。

我不清楚_current_dir的目的是什么。 也許它可以刪除。

這是該功能的更新版本。 _current_dir僅用於在遞歸調用中構造參數的值。

int list_dirs (const std::string& _dir,
               std::vector<std::string>& _files, std::string _current_dir){
   std::vector<std::string> __files_or_dirs;

   list_dir(_dir, __files_or_dirs);

   std::vector<std::string>::iterator it = __files_or_dirs.begin();
   struct stat sb;

   for (; it != __files_or_dirs.end() ; ++it){
      std::string entry = *it;
      std::string full_path = _dir + "/" + entry;

      if (lstat(full_path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){
         /* how to do this better? */

         /* here it should go into sub-directory */
         list_dirs(full_path, _files, _current_dir + "/" + entry);

      } else {
         _files.push_back(full_path);
      }
   }
}

我不確定你的代碼中的所有問題,但我可以告訴你,這一行和另一個類似於它會導致你的問題:

__files_or_dirs.erase(it);

當你調用erase你會在擦除點或之后使迭代器和引用無效,包括end()迭代器(參見這個擦除引用 )。 你正在調用erase然后不存儲返回的迭代器,然后在這次調用之后再次查看它,這不是一件好事。 您至少應該將行更改為此,以便捕獲返回的迭代器,該迭代器應指向擦除元素之后的元素(如果它是最后一個元素,則指向end()

it = __files_or_dirs.erase(it);

從您發布的代碼中也可以看出, _dir_current_dir之間_dir冗余。 您不要修改它們中的任何一個。 您將它們作為相同的值傳遞,並且它們在整個函數執行期間保持相同的值。 除非這是簡化的代碼並且您正在做其他事情,否則我建議您刪除_current_dir並只使用_dir 您可以使用_dir替換while循環中的_dir ,您將構建文件名,並且您將簡化代碼,這始終是一件好事。

對於這一行:

   if (lstat((&*it)->c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){

請注意, readdir和因此list_dir僅返回文件 ,而不是完整文件路徑。 所以此時(&*it)->c_str()只有一個文件名(例如“input.txt”),而不是完整路徑,所以當你在子目錄中的文件上調用lstat時,系統不能找到它。

要解決此問題,您需要在調用lstat之前添加文件路徑。 就像是:

   string fullFileName;
   if (dir.empty()){
       fullFileName = *it;
   } else {
       fullFileName = dir + "/" + *it;
   }

   if (lstat(fullFileName.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)){

您可能必須使用_currentDir而不是dir ,具體取決於它們的實際用途(我無法按照您的解釋)。

Linux上更簡單的方法是使用nftw(3)函數。 它以遞歸方式掃描文件樹,並為其提供一些處理函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM