简体   繁体   中英

iterating through all the directories and subdirectories in c++

I wanted to use the std::filesystem::recursive_directory_iterator class to create a class method iterating through all subdirectories and processing found xml files.

The only way I have found on the internet to do this was using a for loop like this:

for (fs::directory_entry p : fs::recursive_directory_iterator("my_file"))
    do_something(p);

The problem is that i need to store my iterator (or atleast where it's pointing) inbetween function calls as i can only process one file at a time. I tried implementing it like this:

class C {
private:
    std::filesystem::recursive_directory_iterator it;
    std::filesystem::directory_entry p;
public:
    C(std::filesystem::path);
    std::string find_file();
};

C::C(std::filesystem::path path)
{
    it = fs::recursive_directory_iterator(path);
    p = fs::directory_entry(it.begin());
}

std::string C::find_file()
{
    do { //using do while so my function won't load the same file twice
        ++p;
    } while (!is_xml(p.path()) && p != it.end());

}

But it seems that std::filesystem::recursive_directory_iterator doesn't have begin() and end() methods and can't be compared.

I have no idea how my code is different from the working for range loop except for storing the iterator and having an extra condition.

If you look a std::filesystem::recursive_directory_iterator Non-member functions you can see that there is:

// range-based for loop support
begin(std::filesystem::recursive_directory_iterator)
end(std::filesystem::recursive_directory_iterator)

And then std::filesystem::begin(recursive_directory_iterator), std::filesystem::end(recursive_directory_iterator) with more details:

end(recursive_directory_iterator) Returns a default-constructed recursive_directory_iterator, which serves as the end iterator. The argument is ignored.

So you will check if it is not equal to std::end(it) , so see if there are any more elements. And you have to increment it and not p .

You also need to check if it != std::end(it) before you do !is_xml(*it.path())

std::string C::find_file()
{
    do { //using do while so my function won't load the same file twice

        ++it;
    } while (it != std::end(it) && !is_xml(*it.path()));

}

recursive_directory_iterator is already an iterator by itself (it says so right in its name), so you don't need to use begin() and end() at all. It implements operator== , operator!= , operator-> , and operator++ , which are all you need in this case.

Also, there is no reason for p to be a class member at all. It should be a local variable of find_file() instead (actually, in this case, it can be eliminated completely). And the loop should be a while loop instead of a do..while loop, in case the iterator is already at its "end" when find_file() is entered.

Try this instead:

class C {
private:
    std::filesystem::recursive_directory_iterator it;
public:
    C(std::filesystem::path);
    std::string find_file();
};

C::C(std::filesystem::path path)
    : it(path)
{
}

std::string C::find_file()
{
    static std::filesystem::directory_iterator end;
    while (it != end) {
        auto p = it->path();
        if (is_xml(p))
            return p.string();
        ++it;
    }
    return "";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM