Home > OS >  C : Closing specific ifstreams in a global vector with just the file name
C : Closing specific ifstreams in a global vector with just the file name

Time:11-15

For this project I have to open a file with an ifstream in one function. The code i have written can be seen below:

bool FileReader::openFile(std::string fileName) {

std::ifstream inFile;
streams.push_back(std::move(inFile));

if (streams.back().is_open()) {
    std::cout << "File Found";
    return true;
}
else {
    std::cout << "File Not Found";
    return false;
}

and then close it in another function. Here is that empty function:

bool FileReader::closeFile(std::string fileName) {

return false;
}

Both of these functions work by passing in the file path as a parameter and the ifstreams are stored in a global vector so multiple files can be open at once

What I dont understand is how i can close one of those streams with just the filename as a paramater.

Any help would be greatly appreciated

CodePudding user response:

There is no direct and portable way to get the file name of a std::ifstream. You can use a map instead of a vector, to reference streams with their filename.

Example using std::unordered_map<>:

#include <fstream>
#include <string>
#include <unordered_map>

class FileReader
{
    // ...
    std::unordered_map<std::string, std::ifstream> streams_;

    // ...

    // attempts to open fie fileName, and adds it to map of streams. 
    //
    // returns:
    //   - true on success
    //   - false if file is already opened or could not be opened.
    //
    bool openFile(const std::string& fileName)
    {
        if (streams_.find(fileName) != streams_.end())
            return false;

        auto ifs = std::ifstream{fileName};

        if (!ifs.is_open())
            return false;

        streams_.emplace(fileName, std::move(ifs));
        return true;
    }

    bool closeFile(const std::string& fileName) 
    {
        auto pos = streams_.find(fileName);
        if (pos == streams_.end())
            return false;

        streams_.erase(pos);
        return true;
    }
};

Note that, unlike your example, the variable containing the streams is in a scope that is visible to both openFile() and closeFile().

CodePudding user response:

There is no direct way to get the name of a std::fstream.. You can use a map instead of a vector, to reference streams with their filename.

Example using std::unordered_map<>:

#include <fstream>
#include <string>
#include <unordered_map>

class FileReader
{
    // ...
    std::unordered_map<std::string, std::ifstream> streams_;

    // ...

    // attempts to open fie fileName, and adds it to map of streams. 
    //
    // returns:
    //   - true on success
    //   - false if file is already opened or could not be opened.
    //
    bool openFile(const std::string& fileName)
    {
        if (streams_.find(fileName) != streams_.end())
            return false;

        auto ifs = std::ifstream{fileName};

        if (!ifs.is_open())
            return false;

        streams_.emplace(fileName, std::move(ifs));
        return true;
    }

    bool closeFile(const std::string& fileName) 
    { 
        if (auto pos = streams_.find(fileName); pos != streams_.end())
        {
            streams_.erase(pos);
            return true;
        }
        return false;
    }
};

Note that, unlike your example, the variable containing the streams is in a scope that is visible to both openFile() and closeFile().

  • Related