2017-10-11 20 views
1

こんにちは皆私はここで初心者です。私はこの問題を投稿したいと思っていました。ドライブ内の特定の拡張子を持つすべてのファイルのリストを取得する方法は?

特定のファイルタイプを検索するすべてのフォルダとサブフォルダを再帰的に繰り返すC++プログラムを開発しています。

最初に、機能FindFiles(string, string, bool)は魅力的ですが、その2番目の形式FindFiles(struct var)はうまく動作しません。すべてのフォルダとサブフォルダに対して繰り返し処理を行いません。実際に

検索が長すぎるかもしれないという事実として、私はAPI CreateThreadでスレッドを作成し、LPVOIDとしてそれを私のarguments structを渡す必要があるので、私は2番目のフォームを必要としています。

#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); 
    } 
} 

それは私のものなので2番目のフォームをご覧ください。私はそこにいくつかの愚かな間違いがあると思う。

本当にありがとうございました。サブフォルダを検索するときに、それは常に偽であるので、それはar.bRecurseフラグを変更しているので、

+0

@RemyLebeau:あなたができるように、実際には最初の形式は、私はインターネットでどこかにそれを見つけました私はそれを編集して2番目のフォームを作っているのを見てください。しかし、あなたが私にいくつかの選択肢をアドバイスしたら、本当に感謝しています。ありがとう! – 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バージョンが再帰しません:FindFiles()

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

3-のparamsバージョンにはありません

:最も簡単な解決策は、その最初の FindFiles()呼び出しの後に戻ってtrueに ar.bRecurseをリセットすることです

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! 
} 

:それを行います210

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

関連する問題