Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fstream fails to create new file

Tags:

c++

file

file-io

I'm using a FileManager for a project so that reading and writing is less of a hassle for me. Or would be, if I didn't spend all this time debugging it. So, this comfort-class actually caused me stress and time. Awesome.

The problem seems to be the fstream. Before I continue further, here is the structure of my FileManager class.

class FileManager : Utility::Uncopyable
{
public:
    FileManager();

    void open(std::string const& filename);
    void close();

    void read(std::string& buffer);
    void write(std::string const& data);

private:
    std::fstream stream_;
};

Very simple. The buffer is loaded with data during the read function, the data parameter is what's to be written to file. Before reading and writing you must open the file or risk getting a big, fat exception in your face. Kind of like the one I'm getting now.

Scenario: Simple command-line registering of a user, then writing the data to file. I ask for a name and password. The name is copied and appended with .txt (the filename). So it looks like this:

void SessionManager::writeToFile(std::string const& name, 
                                 std::string const& password)
{
    std::string filename = name + ".txt";
    std::string data;
    data += name +", " +password;

    try
    {
        fileManager_->open(filename);
        fileManager_->write(data);
        fileManager_->close();
    } 
    catch(FileException& exception)
    {
        /* Clean it up. */
        std::cerr << exception.what() << "\n";
        throw;
    }
}

Problem: the open fails. The file is never created, and during the write I get an exception for not having an open file.

FileManager::open() function:

void FileManager::open(std::string const& filename)
{
    if(stream_.is_open())
        stream_.close();

    stream_.open(filename.c_str());
}

and write

void FileManager::write(std::string const& data)
{
    if(stream_.is_open())
        stream_ << data;
    else
        throw FileException("Error. No file opened.\n");
}

However, if I create the file beforehand, then it has no troubles opening the file. Yet, when I check, the default std::ios::openmode is std::ios::in | std::ios::out. I can create the file just fine when I only tag std::ios::out, but I want to keep the stream in a read/write state.

How can I accomplish this?

like image 382
IAE Avatar asked Jan 26 '11 15:01

IAE


2 Answers

Best method:

void FileManager::open(std::string const& filename)
{
    using std::ios_base;
    if( stream_.is_open() )
        stream_.close();

    stream_.open( filename.c_str() ); // ...try existing file
    if( !stream_.is_open() ) // ...else, create new file...
        stream_.open(filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc);
}

So the code tests for an existing file and, if not, creates it.

like image 173
AtesComp Avatar answered Oct 18 '22 04:10

AtesComp


You have to call fstream::open with an explicit openmode argument of

ios_base::in | ios_base::out | ios_base::trunc

Otherwise open will fail due to ENOENT.

Table 95 of the draft C++ standard lists possible file open modes and their equivalent in stdio. The default, ios_base::out | ios_base::in is r+. The one I listed above is equivalent to w+. ios_base::out | ios_base::app is equivalent to a. All other combinations involving ios_base::app are invalid.

(At the risk of being scoffed at: you could switch to stdio and use the file mode a+, which reads from the start and appends at the end.)

like image 23
Fred Foo Avatar answered Oct 18 '22 03:10

Fred Foo