Pichuu64
Pichuu64

Reputation: 83

Utilizing the <filesystem> library; visualStudios

I'll cut the the short of it. I'm attempting to understand the filesystem library but there's very little information I've been able to find. I managed to get it to compile and understand the filesystem::path type variable really well but don't seem to understand how to get filesystem::directory_iterator to work properly. I'm not sure if I'm using it for a purpose it wasn't design for. So here is what I'm attempting to do:

I wanted to create a program that opens every text file within a specified folder. For this I need to obtain the folder name and path but I want the program to be able to obtain this information on itself and dynamically so if I add or remove textFiles it'll have the logic to function.

I'm able to create a directory_iterator variable that it manages to hold the first file with me just giving it the directory like this:

const char address[]{ "C:\\Users\\c-jr8\\ProgramBranch\\PersonalPlatform\\log extruder\\logs" };

fs::directory_iterator myIterator(address);

When testing the code in the folder I have four textFiles called "attempt 1" to "attempt 4". When reading the information on:

https://learn.microsoft.com/en-us/cpp/standard-library/directory-iterator-class?view=vs-2019#op_star

It mentions two functions to move the path object within the iterator to the next file. The first is increment(), which is the intendent method for iterating through the files, and operation++().

Now increment() hasn't been able to work for me cause it takes in a erro_code type variable and I haven't been able to find much information about how to implement this with the filesystem_errorcode variable or however it's meant to be used. The operation++() works beautifully and provides me with the path to every file but I was having issues with managing the code to detect when the operate++() functions leads to no other files. Once it iterates through every file it sorts of crashes when it keeps moving to the next. Here's that piece of code:

string tempString;
for (int i = 0; i < 5; i++) { //Here the limiting is 5 so it'll iterate onces more than the numbers of files unpurpose to see how it responses.
    tempString = myIterator.operator*().path().generic_string();
    ifstream tempFile(tempString);

    if (!tempFile.is_open()) {
        cout << "Looking at file: " << i + 1 << "; failed to open." << endl << endl;
        cin.get();
        return 0;
    }

    {
        //do things with file...
    }

    tempFile.close();
    myIterator.operator++();
}

What I want if to find a way to stop the for loop once it the iterator goes off the final file.

whichever information about how the filesystem library works it would be very much appreciated.

Upvotes: 0

Views: 66

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 117643

You should compare myIterator with a default constructed directory_iterator to check if the last file has been processed. You can also use a much simpler form to access the operators (shown in the code below):

string tempString;

// loop until myIterator == fs::directory_iterator{}
for(size_t i = 1; myIterator != fs::directory_iterator{}; ++i) {

    // access path() through the iterators operator-> 
    tempString = myIterator->path().generic_string();
    ifstream tempFile(tempString);

    if(!tempFile.is_open()) {
        cout << "Looking at file: " << i << "; failed to open." << endl << endl;
        cin.get();
        return 0;
    }
    {
        std::cout << tempString << " opened\n";
    }

    // tempFile.close(); // closes automatically when it goes out of scope

    // simpler form to use myIterator.operator++():
    ++myIterator;
}

An even simpler approach would be to use a range-based for-loop:

for(const fs::directory_entry& dirent : fs::directory_iterator(address)) {
    const fs::path& path = dirent.path();
    ifstream tempFile(path);

    if(!tempFile) {
        cout << "Looking at file: " << path << "; failed to open.\n\n";
        cin.get();
        return 0;
    }
    std::cout << path << " opened\n";
}

Upvotes: 1

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48487

std::directory_iterator is a classic iterator that allows for iterating over ranges, and those are usually designated by a pair of iterators, one indicating the beginning of a sequence and another representing the past-the-end iterator.

Some iterator types, like those providing access to streams, don't have an actual end location in memory. A similar situation applies to a directory iterator. In such a case, the idiomatic approach is to use a default-constructed iterator object that will serve as an end indicator.

Having said that, you could rewrite your loop to:

for (fs::directory_iterator myIterator(address), end{}; myIterator != end; ++myIterator) {

Alternatively, you can utilize a range-based for loop:

for (auto& p : fs::directory_iterator(address)) {
    tempString = p.path().generic_string();
    // ...

Also, note that iterators' interface is supposed to look/behave like a pointer, hence it uses operator overloading to allow for concise syntax. So instead of:

myIterator.operator++();

you should be using:

++myIterator;

Similarly, instead of:

myIterator.operator*().path().generic_string();

juse use:

(*myIterator).path().generic_string();

or:

myIterator->path().generic_string();

Upvotes: 1

Related Questions