2017-10-11 101 views
1

你好,我是新手。经过漫长的绝望搜索,我想发布这个问题:如何获得具有特定扩展名的驱动器中的所有文件的列表?

我正在开发一个C++程序,递归遍历所有搜索特定文件类型的文件夹和子文件夹。

首先功能FindFiles(string, string, bool)工作像一个魅力,但它的第二种形式FindFiles(struct var)不能正常工作:它不会遍历所有文件夹和子文件夹。

事实上,我需要第二种形式,因为由于搜索可能太长,我需要使用API​​ CreateThread创建线程,并将我的arguments struct作为LPVOID传递给它。

#include <windows.h> 
#include <string> 
#include <iostream> 
using namespace std; 



// Arguments struct 
struct args{ 
    string strDir; 
    string strFilter; 
    bool bRecurse; 
}; 


void FindFiles(string strDir, string strFilter, bool bRecurse); 
void FindFiles(args); 


int main(){ 

// FindFiles("D:", "*.mp3", true); // works fine 

    args ar; 
    ar.bRecurse = true; 
    ar.strDir = "D:"; 
    ar.strFilter = "*.mp3"; 

    FindFiles(ar); // doesn't work fine 

    cout << endl; 
    return 0; 
} 

void FindFiles(string strDir, string strFilter, bool bRecurse = true){ 
    if(bRecurse) 
     FindFiles(strDir, strFilter, false); 
    strDir += "\\"; 
    WIN32_FIND_DATA wfd; 

    string strFileFilter = strDir + (bRecurse ? "*" : strFilter); 
    HANDLE hFile = FindFirstFile(strFileFilter.c_str(), &wfd); 

    if(INVALID_HANDLE_VALUE == hFile) 
     return; 
    else{ 
     if(!bRecurse) 
      cout << strDir + string(wfd.cFileName) << endl; 
     while(FindNextFile(hFile, &wfd)){ 
      if(!bRecurse) 
       cout << strDir + string(wfd.cFileName) << endl; 
      else{ 
       if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0 && 
        wfd.cFileName[0] != '.') 
        FindFiles(strDir + string(wfd.cFileName), strFilter, true); 
      } 
     } 
    // FindClose(hFile); 
    } 
} 

void FindFiles(args ar){ 
    if(ar.bRecurse){ 
     ar.bRecurse = false; 
     FindFiles(ar); 
    } 
    ar.strDir += "\\"; 
    WIN32_FIND_DATA wfd; 

    string strFileFilter = ar.strDir + (ar.bRecurse ? "*" : ar.strFilter); 
    HANDLE hFile = FindFirstFile(strFileFilter.c_str(), &wfd); 

    if(INVALID_HANDLE_VALUE == hFile) 
     return; 
    else{ 
     if(!ar.bRecurse) 
      cout << ar.strDir + string(wfd.cFileName) << endl; 
     while(FindNextFile(hFile, &wfd)){ 
      if(!ar.bRecurse) 
       cout << ar.strDir + string(wfd.cFileName) << endl; 
      else{ 
       if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0 && 
        wfd.cFileName[0] != '.'){ 
         ar.strDir += string(wfd.cFileName); 
         ar.bRecurse = true; 
         FindFiles(ar); 
       } 
      } 
     } 
     FindClose(hFile); 
    } 
} 

请看看第二个表格,因为它是我的。我认为那里有一些愚蠢的错误。

任何帮助我真的很感激它。

+0

@RemyLebeau:其实第一种形式,我发现它的地方在互联网上,从而可以看到我编辑它作为第二种形式。但是,如果你建议我一些替代品,那么我真的很感激它。感谢名单! – WonFeiHong

+0

你正在尝试*方式*太难。使用[recursive_directory_iterator](https://docs.microsoft.com/en-us/cpp/standard-library/recursive-directory-iterator-class)为您完成这项工作。此外,在本地使用Unicode的文件系统上对文件名使用ANSI/MBCS编码是一个错误。 – IInspectable

+0

@IInspectable:可以解释更多关于错误的信息。 Thanx为有用的链接。 – WonFeiHong

回答

4

你的FindFiles() 1 PARAM版本不递归,因为它修改ar.bRecurse标志,因此搜索子文件夹时总是假的:

void FindFiles(args ar){ 
    if(ar.bRecurse){ 
     ar.bRecurse = false; // <-- modified! 
     FindFiles(ar); 
    } 
    ... 
    // ar.bRecurse is still false here! 
} 

FindFiles()三PARAMS版本不做到这一点:

void FindFiles(string strDir, string strFilter, bool bRecurse = true){ 
    if(bRecurse) 
     FindFiles(strDir, strFilter, false); // <-- bRecurse is not modified here! 
    ... 
    // bRecurse is still the original value here! 
} 

最简单的办法是,初始FindFiles()通话后重置ar.bRecurse回真:

void FindFiles(args ar){ 
    if(ar.bRecurse){ 
     ar.bRecurse = false; // <-- modified! 
     FindFiles(ar); 
     ar.bRecurse = true; // <-- reset here! 
    } 
    ... 
} 

或使用该调用一个临时的结构:

void FindFiles(args ar){ 
    if(ar.bRecurse){ 
     args arTmp = ar; // <-- temp copy! 
     arTmp.bRecurse = false; // <-- modify the copy! 
     FindFiles(arTmp); 
    } 
    ... 
    // ar.bRecurse is still the original value here! 
} 

现在,这么说,你并不真的需要在功能上,在所有bRecurse检查。它实际上只是在输入文件夹中扫描匹配的文件,然后再次扫描该文件夹才能找到子文件夹。您可以通过使用一个单一的搜索和本地缓存的子文件夹旁边的搜索,完成同样的逻辑如:

#include <windows.h> 

#include <string> 
#include <iostream> 
#include <vector> 

using namespace std; 

// Arguments struct 
struct args 
{ 
    string strDir; 
    string strExt; 
    bool bRecurse; 
}; 

void FindFiles(const string &strDir, const string &strExt, bool bRecurse = true); 
void FindFiles(const args &ar); 

int main() 
{  
    // FindFiles("D:", ".mp3", true); 

    args ar; 
    ar.strDir = "D:"; 
    ar.strExt = ".mp3"; 
    ar.bRecurse = true; 

    FindFiles(ar); 

    cout << endl; 
    return 0; 
} 

void FindFiles(const string &strDir, const string &strExt, bool bRecurse) 
{ 
    string strSearchDir = strDir; 
    vector<string> vDirs; 

    if (!strSearchDir.empty()) 
    { 
     switch (strSearchDir[strSearchDir.size()-1]) 
     { 
      case '\\': 
      case '/': 
       break; 
      default: 
       strSearchDir += "\\"; 
       break; 
     } 
    } 

    WIN32_FIND_DATAA wfd = {}; 

    HANDLE hFile = FindFirstFileA((strSearchDir + "*.*").c_str(), &wfd); 
    if (INVALID_HANDLE_VALUE == hFile) 
     return; 

    do 
    { 
     string strFilename(wfd.cFileName); 

     if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
     { 
      if ((strFilename == ".") || (strFilename == "..")) 
       continue; 

      if (bRecurse) 
       vDirs.push_back(strSearchDir + strFilename); 
     } 
     else 
     { 
      if (!strExt.empty()) 
      { 
       if (strFilename.size() < strExt.size()) 
        continue; 

       if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, strFilename.c_str()+(strFilename.size()-strExt.size()), strExt.size(), strExt.c_str(), strExt.size()) != 2) 
        continue; 
      } 

      cout << strSearchDir << strFilename << endl; 
     } 
    } 
    while (FindNextFile(hFile, &wfd)); 

    FindClose(hFile); 

    if (bRecurse) 
    { 
     for(vector<string>::iterator iter = vDirs.begin(), end = vDirs.end(); iter != end; ++iter) 
      FindFiles(*iter, strExt, true); 
    } 
} 

void FindFiles(const args &ar) 
{ 
    FindFiles(ar.strDir, ar.strExt, ar.bRecurse); 
} 
+0

非常感谢。我尝试过它,它的功能就像一个魅力。你太有建设性。明天我会检查你的整个代码,现在我太困了。 – WonFeiHong

+0

对不起,我没有足够的分数投票。 – WonFeiHong

+0

是的,真的是这个问题当我修改'ar.bRecurse'时,它在子文件夹中总是为false。但我不明白为什么? – WonFeiHong

相关问题