フォルダ内の各ファイルをfor文で処理する

C++11ではfor文に新たな記法が追加され、便利になりました。 新しい記法ではイテレーターを返すbegin()とend()を持っているものなら何でも回すことができます。 イテレーターを自作することでfor文で書けるものを増やすことができます。

今回はDXライブラリの隠しAPIであるファイル検索APIイテレーターでラップしてみました。 あるフォルダ内で特定の拡張子を持つファイルを探す、といった処理が簡単に書けます。

for(FILEINFO& file : findFile("*.*")){
    printfDx("%s\t%d\n", file.Name, file.Size);
}

この例ではフォルダ内のすべてのファイルの名前とサイズを表示しています。 簡単ですね。

FILEINFOの部分はautoでもOKです。

for(auto& file : findFile("save/*.sav")){
    printfDx("%s\t%d\n", file.Name, file.Size);
}

saveフォルダ内のsavファイルを列挙。

昔のC++で書く場合は次のようにします。

FileSearchState state = findFile("save/*.sav");
for(FileSearchState::iterator& file = state .begin(); file != state.end(); ++file){
    printfDx("%s\n", file->Name);
}

大変ですね。

実装

#include <DxLib.h>
#include <iostream>
#include <vector>
#include <string>

class FileSearchState{
public:
    class iterator : public std::iterator<std::input_iterator_tag, std::string>{
    public:
        iterator(const char* path):isValid(false){
            if(path == nullptr){
                findhandle = -1;
                isValid = false;
            }else{
                findhandle = FileRead_findFirst(path, &fileinfo);
                isValid = (findhandle != -1);
            }
        }
        ~iterator(){
            if(findhandle != -1){
                FileRead_findClose(findhandle);
            }
        }
        const FILEINFO& operator*() const { return fileinfo; }
        const FILEINFO* operator->() const { return &fileinfo; }
        iterator& operator++() {
            isValid = (FileRead_findNext(findhandle, &fileinfo) != -1);
            return *this;
        }
        bool operator==(const iterator &x) const {
            return (isValid && x.isValid && findhandle == x.findhandle) || (!isValid && !x.isValid);
        }
        bool operator!=(const iterator &x) const { return !(*this == x); }
    private:
        FILEINFO fileinfo;
        int findhandle;
        bool isValid;
    };

    FileSearchState(const char* path){
        this->path = path;
    }

    iterator begin() const{
        return iterator(path);
    }

    iterator& end() const{
        static iterator endItr(nullptr);
        return endItr;
    }
private:
    const char* path;
};

FileSearchState findFile(const char* path){
    return FileSearchState(path);
}
FileSearchState findFile(const std::string path){
    return FileSearchState(path.c_str());
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
    ChangeWindowMode(true);
    SetMainWindowText("DxLibProject1");
    SetGraphMode(640, 480, 32, 60);

    if(DxLib_Init() == -1){
        return -1;
    }

    for(auto& file : findFile("*.*")){
        printfDx("%s\t%d\n", file.Name, file.Size);
    }

    WaitKey();

    DxLib_End();
    return 0;
}