最下層にあるフォルダのパスを取得するには?

解決


くにえー  2002-11-26 15:27:36  No: 50728  IP: [192.*.*.*]

お初にお目にかかります。
題名だけではまったく意味がわかんないですね(^-^;)説明します。

MFC ダイアログベースで作成しています。
まず、入力されたある場所までのパスを取得し(例 C:\Program Files)、
それより下の最下層のフォルダのパスを取得してくるというものを作っています。
イマイチ巧く説明できません…エクスプローラのツリーでいうと、
フォルダアイコンの前に「+」がつかないフォルダです。

このパスを効率よくメモリかファイルに格納させたいのですが、よいものが浮かびません。
知恵を貸してもらえませんでしょうか?

それと、この最下層のフォルダは5000〜10000こあるようなのですが、
これだとメモリに格納するよりファイルに格納したほうがよいでしょうか?

編集 削除
YuO  2002-11-26 17:34:24  No: 50729  IP: [192.*.*.*]

とにかくCFindFileクラスで再帰,というのが手段になるでしょうね。
5000 - 10000程度,今のマシンならメモリに蓄えても問題ないです。

私の趣味に走ると,次のような感じになります。
効率よりも書き易さ重視です(どこがだ)。
決して真似しないでください。見たことがないC++の構文がたくさん出てきているでしょうけど……。
#一応,ANSI/UNICODE両対応です。独自アロケータだろうが問題なく動きます。

template <typename T> struct traits;
template <> struct traits<char> {
    typedef WIN32_FIND_DATAA win32_find_data;
    static const char * const dot_file;
    static const char * const double_dot_file;
    static const char asterisk;
    static const char reverse_solidus;
};
template <> struct traits<wchar_t> {
    typedef WIN32_FIND_DATAW win32_find_data;
    static const wchar_t * const dot_file;
    static const wchar_t * const double_dot_file;
    static const wchar_t asterisk;
    static const wchar_t reverse_solidus;
};

const char * const traits<char>::dot_file = ".";
const char * const traits<char>::double_dot_file = "..";
const char traits<char>::asterisk = '*';
const char traits<char>::reverse_solidus = '\\';
const wchar_t * const traits<wchar_t>::dot_file = ".";
const wchar_t * const traits<wchar_t>::double_dot_file = "..";
const wchar_t traits<wchar_t>::full_stop = '.';
const wchar_t traits<wchar_t>::asterisk = L'*';
const wchar_t traits<wchar_t>::reverse_solidus = L'\\';

inline HANDLE findFirstFile (const char * file, WIN32_FIND_DATAA & wfd)
{
    return ::FindFirstFileA(file, &wfd);
}
inline HANDLE findFirstFile (const wchar_t * file, WIN32_FIND_DATAW & wfd)
{
    return ::FindFirstFileW(file, &wfd);
}

inline bool findNextFile (HANDLE hFind, WIN32_FIND_DATAA & wfd)
{
    return ::FindNextFileA(hFind, &wfd) != FALSE;
}
inline bool findNextFile (HANDLE hFind, WIN32_FIND_DATAW & wfd)
{
    return ::FindNextFileW(hFind, &wfd) != FALSE;
}

inline bool findClose (HANDLE hFind)
{
    return ::FindClose(hFind) != FALSE;
}

template <typename T, class CT, class AT, class AV>
bool findFiles (const std::basic_string<T, CT, AT> & base, std::vector<std::basic_string<T, CT, AT>, AV> & result)
{
    typedef traits<T> traits_type;
    typedef traits_type::win32_find_data wfd_type;
    typedef std::basic_string<T, CT, AT> string_type;

    wfd_type wfd;
    HANDLE hFind;
    bool ret = false;

    hFind = findFirstFile(string_type(base).append(1, traits_type::asterisk).c_str(), wfd);
    if (hFind == INVALID_HANDLE_VALUE) return false;

    do {
        if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) continue;
        if (CT::compare(wfd.cFileName, traits_type::dot_file, 2) == 0 || CT::compare(wfd.cFileName, traits_type::double_dot_file, 3) == 0) continue;

        if (!findFiles((base + wfd.cFileName).append(1, traits_type::reverse_solidus), result)) {
            result.push_back(base + wfd.cFileName);
        }
        ret = true;
    } while (findNextFile(hFind, wfd));
    findClose(hFind);
    return ret;
}

ちなみに,findFilesをcharについて展開すると,次のようになります。

bool findFiles (const std::string & base, std::vector<std::string> & result)
{
    WIN32_FIND_DATAA wfd; // WIN32_FIND_DATAA : WIN32_FIND_DATA for ANSI
    HANDLE hFind;
    bool ret = false;

    hFind = FindFirstFileA((base + "*").c_str(), &wfd); // FindFirstFileA : FindFirstFile for ANSI
    if (hFind == INVALID_HANDLE_VALUE) return false;

    do {
        if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) continue;
        if (std::strcmp(wfd.cFileName, ".") == 0 || std::stdcmp(wfd.cFileName, "..") == 0) continue;

        if (!findFiles(base + wfd.cFileName + "\\", result)) {
            result.push_back(base + wfd.cFileName);
        }
        ret = true;
    } while (FindNextFileA(hFind, &wfd)); // FindNextFileA : FindNextFile for ANSI
    FindClose(hFind);
    return ret;
}

こっちならわかりよいかと。たぶん,再帰を潰してもそれほど効果はないでしょう。

編集 削除
YuO  2002-11-26 17:45:38  No: 50730  IP: [192.*.*.*]

細々とミスった……。

> const wchar_t * const traits<wchar_t>::dot_file = ".";
> const wchar_t * const traits<wchar_t>::double_dot_file = "..";
> const wchar_t traits<wchar_t>::full_stop = '.';
は,
const wchar_t * const traits<wchar_t>::dot_file = L".";
const wchar_t * const traits<wchar_t>::double_dot_file = L"..";
です。
#full_stopはCT::compareを使わずに書いた頃の名残。

編集 削除
くにえー  2002-11-28 13:22:27  No: 50731  IP: [192.*.*.*]

YuOさん、解答ありがとうございます!
でもおっしゃる通り見たこと無いものがいっぱい…
結局YuOさんが書かれた物は解読できませんした><
折角解答していただいたのにすみません…

でも、CFindFileを使って再帰で処理すればよいという事はわかったので、
がんばってみたいと思います!

編集 削除
YuO  2002-11-28 16:19:43  No: 50732  IP: [192.*.*.*]

> でもおっしゃる通り見たこと無いものがいっぱい…
> 結局YuOさんが書かれた物は解読できませんした><

templateに慣れていると問題ないんですけどね……。
まぁ,普通のC++の入門書ではtemplateの特殊化まで扱っていませんし。
MFCに慣れていると,標準C++ライブラリのクラスや関数も知らないかもしれませんね。
std::string使わずにCString使ったりしますから。

ただ,
>bool findFiles (const std::string & base, std::vector<std::string> & result)
の方はある程度読めた方がいいですよ。
Win32 APIと標準C++ライブラリを利用したプログラムです。


> 折角解答していただいたのにすみません…

いえ,プログラムコードに関しては本当に「趣味に走った」ものですから,
読めなくても問題ないと思います。

編集 削除
くにえー  2002-11-28 17:00:38  No: 50733  IP: [192.*.*.*]

YuOさんまたまたありがとうございます。

> templateに慣れていると問題ないんですけどね……。
私は今年入社して初めてVCを触ったもので、教えてもらっている先輩に
「お前には、templateはまだ早い。MFCをみっちりやっとけ」
と言われたもので存在は知ってても必要最小限しか触ってないんです…

> >bool findFiles (const std::string & base, std::vector<std::string> & result)
> の方はある程度読めた方がいいですよ。
あの書き込みの後、こちらの方をじーっくり読んで何とか解読できました。
こちらを参考にして、使いたい形にアレンジさせていただいて何とか実現できました。

これからもお世話になるかもしれませんが、宜しくお願いします。
ありがとうございました!

#YuOさんって何にでも解答を出していてスーパーマンみたいに見えるっす!w
#失礼しましたm(_ _)m

編集 削除