递归函数不返回正确的值

时间:2014-12-19 15:12:25

标签: visual-c++ recursion

我有一个递归函数。它对文件夹进行递归搜索,在第一个参数中给出的驱动器或文件夹内的第二个参数中给出了该名称。第二个参数中给出的文件夹可以位于第一个参数中给出的驱动器或文件夹内的任何路径和任何嵌套级别。 因此,函数浏览第一个参数中指定的驱动器或文件夹的所有内容,以查找第二个参数中指定的文件夹以下是功能本身:

wstring FolderPathValidator::FindRequiredFolder(const wstring& p_InitialPath, wstring p_RequiredFolderName)
{
      wstring foundFolder = L"";
      wstring folderPath = p_InitialPath + L"\\*";
      WIN32_FIND_DATAW folderInfo;
      HANDLE search_handle = FindFirstFileW(folderPath.c_str(), &folderInfo);
      if (search_handle != INVALID_HANDLE_VALUE)
      {
           vector<wstring> folders;

           do
           {
                if (folderInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                     if ((!lstrcmpW(folderInfo.cFileName, L".")) || (!lstrcmpW(folderInfo.cFileName, L"..")))
                     continue;
                }

                folderPath = p_InitialPath + L"\\" + wstring(folderInfo.cFileName);

                if (folderInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                     if (folderInfo.cFileName == p_RequiredFolderName)
                     {
                          foundFolder = folderInfo.cFileName;
                          return foundFolder;
                     }
                     folders.push_back(folderPath);
                }
           } while (FindNextFileW(search_handle, &folderInfo));

           ::FindClose(search_handle);

           for (vector<wstring>::iterator iter = folders.begin(), end = folders.end(); iter != end; ++iter)
               FindRequiredFolder(*iter, p_RequiredFolderName);
      }

      return foundFolder;
}

在代码中我用以下方式调用它:

wstring FoundFolder = FindRequiredFolder(L"C:", L"TextFiles_to_Test");

但是,如果我将我的函数指向正确的方式(第二个参数中给出的文件夹存在),则返回一个空字符串。我应该如何更正代码,以便函数返回找到的文件夹。

我补充一点,我逐步检查调试器,在那里我看到该函数找到了所需的文件夹,但在其调用操作符中返回一个空字符串。

4 个答案:

答案 0 :(得分:2)

试试这个:

wstring FoundFolder = FindRequiredFolder(L"C:\\", L"TextFiles_to_Test");

您正在以“C:”驱动器的当前工作目录开始搜索 - 而不是C:驱动器的 root 目录。

答案 1 :(得分:0)

您的问题是,当您到达所需的文件夹名称时,您没有返回正确的内容 -

if (folderInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
        if (folderInfo.cFileName == p_RequiredFolderName)
        {
            return folderPath;  // <-- return the found (fully qualified) path name
        }
        // else
        folders.push_back(folderPath);
}

这种方法可能会遇到一些问题(您可能已经考虑过这些问题): 首先,这将返回第一个匹配,无论它出现在树中的哪个位置。考虑:

    c:\a\system
    c:\windows\system
    c:\tmp\system

这对您来说可能是一个问题 此外,它需要相当长的时间。我找了foo1219,我刚刚在c:\tmp中创建了它并且花了一段时间(回收站,文档,程序文件等,都是昂贵的)。如果您有任何用户界面,则可能需要使用对话框并让用户选择文件夹。常用对话框文件对话框可能非常有用。

答案 2 :(得分:0)

这将返回与p_RequiredFolderName匹配的第一个文件夹的完全限定路径。如果p_RequiredFolderName不存在,则返回空字符串:

wstring FindRequiredFolder(const wstring& p_InitialPath, const wstring& p_RequiredFolderName)
{
    wstring foundFolder;
    wstring searchSpec = p_InitialPath + L"\\*";
    WIN32_FIND_DATAW folderInfo;
    HANDLE search_handle = ::FindFirstFileW(searchSpec.c_str(), &folderInfo);
    if (search_handle != INVALID_HANDLE_VALUE){
        do{
            if (folderInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
                if ((!lstrcmpW(folderInfo.cFileName, L".")) || (!lstrcmpW(folderInfo.cFileName, L"..")))
                    continue;

                wstring fullPath = p_InitialPath + L"\\" + folderInfo.cFileName;
                if (folderInfo.cFileName == p_RequiredFolderName){
                    foundFolder = fullPath;  // we're done.
                }
                else{
                    foundFolder = FindRequiredFolder(fullPath, p_RequiredFolderName);
                }
                if (foundFolder.length()){
                    break;
                }
            }
        } while (::FindNextFileW(search_handle, &folderInfo));

        ::FindClose(search_handle);
    }
    return foundFolder;
}

答案 3 :(得分:0)

我正在考虑前面提到的关于返回第一个匹配文件夹的警告,所以我把它扔到了一起:

#define UNICODE
#define _UNICODE
#include <windows.h>
#include <vector>
#include <string>

// Find *all* folders in a directory tree with a given name.
// Params:
//    initialPath      location to start search
//    searchForName    name of folder to search for
//    locations        vector in which to put paths for any matches
//  Returns
//    vector containing all matches (if any).  Same as input parameter,
//    helps with performance on recursion (and also RVO).
std::vector<std::wstring> 
FindRequiredFolderLocations(const std::wstring& initialPath, 
                            const std::wstring& searchForName,
                            std::vector<std::wstring>& locations
                           )
{
    std::wstring searchSpec = initialPath + L"\\*";

    WIN32_FIND_DATA folderInfo;
    HANDLE search_handle = ::FindFirstFile(searchSpec.c_str(), &folderInfo);
    if (search_handle != INVALID_HANDLE_VALUE){
        do{
            if (folderInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
                if ((!lstrcmp(folderInfo.cFileName, L".")) || (!lstrcmp(folderInfo.cFileName, L"..")))
                    continue;

                std::wstring fullPath = initialPath + L"\\" + folderInfo.cFileName;
                if (folderInfo.cFileName == searchForName){
                    locations.push_back(fullPath);
                }
                FindRequiredFolderLocations(fullPath, searchForName, locations);
            }
        } while (::FindNextFile(search_handle, &folderInfo));

        ::FindClose(search_handle);
    }
    return locations;
}

// Overload not requiring "locations" vector parameter (see above)
std::vector<std::wstring> 
FindRequiredFolderLocations(const std::wstring& initialPath, 
                            const std::wstring& folderName)
{
    std::vector<std::wstring> result;
    return FindRequiredFolderLocations(initialPath, folderName, result);
}

#ifdef TEST_FRFL
#include <iostream>
void FRFL_Test(const std::wstring& folderName)
{
    std::vector<std::wstring> locations;

    FindRequiredFolderLocations(L"C:",  folderName, locations);
    size_t count = locations.size();
    if (0 == count){
        std::wcout << L"Required folder not found.\n";
    }
    else if (1 == count){
        std::wcout << L"One location found: " << locations[0] << L"\n";
    }
    else{
        std::wcout << L"multiple locations found for required folder name:\n";
        for (auto loc : locations){
            std::wcout << L"\t" << loc.c_str() << L"\n";
        }
        std::wcout << L"Which one do you want?\n";
    }
}

int main()
{
    FRFL_Test(L"!!exists_1_Location");
    FRFL_Test(L"!!exists_several_Locations");
    FRFL_Test(L"!!exists_nowhere");

    return 0;
}

#endif

构建

C:\tmp>cl /nologo /EHsc /W4 /DTEST_FRFL so-findpathw.cpp

执行以下命令以创建测试目录:

C:\tmp>md frfl
C:\tmp>md frfl\a
C:\tmp>md frfl\a\b
C:\tmp>md frfl\a\b\!!exists_1_Location
C:\tmp>md frfl\a\!!exists_several_Locations
C:\tmp>md frfl\a\b\!!exists_several_Locations
C:\tmp>md frfl\!!exists_several_Locations
C:\tmp>md !!exists_several_Locations

输出:

C:\tmp>so-findpathw
One location found: C:\tmp\frfl\a\b\!!exists_1_Location
multiple locations found for required folder name:
      C:\tmp\!!exists_several_Locations
      C:\tmp\frfl\!!exists_several_Locations
      C:\tmp\frfl\a\!!exists_several_Locations
      C:\tmp\frfl\a\b\!!exists_several_Locations
Which one do you want?
Required folder not found.

不知道你是否需要这个,但找到与你正在寻找的目录基本名称相匹配的任何文件夹,无论它实际位于树中的哪个位置打扰了我。我有点像这样迷恋。