How to avoid creating file if no data sent to std::ofstream?

84 Views Asked by At

When C++ creates std::ofstream it instantly and implicitly creates the underlying file.

I am totally fine with this behaviour unless I have a code which only during its run can see if any data at all will be produced.

So, I want to avoid creating empty files when no data sent to them (kind of transactional integrity: no data, no changes on file system).

I see two approaches I don't like much:

  1. See if something was sent to the stream (tellg()) and remove the file if the stream was empty. I don't like to create and delete files (sometimes there are many of them) and remove operation itself puts too much responsibility.
  2. Create std::stringstream, collect output there and create std::ofstream and copy content only in case the stringstream is not empty. Much better, but still requires temporary memory allocation which could be big.

Is there a better solution for this? Am I missing some idea?

In form of code:

#include <fstream>

int main()
{
    std::ofstream ofs("file.txt");

    // Some code that might or might not output to ofs
    // Some other code that might or might not output to ofs
    // Some more code that might or might not output to ofs

    // It would be nice if file is not created if no data sent to ofs
}

So, the code could contain many places where the output will be performed.

1

There are 1 best solutions below

10
0xbachmann On BEST ANSWER

Creating the std::ofstream object with a constructor that takes a filename, opens the file. You can work around this by only providing the filename via open when you actually need to write.

#include <fstream>

int main()
{
    std::ofstream ofs;

    // determine whether you need to write

    if (/*need_to_output*/) {
        ofs.open("file.txt");
    }

    // write to ofs
}

to avoid checking whether the file is opened or not, consider this simple wrapper class

class lazy_open_ofstream {
public:
    explicit lazy_open_ofstream(std::string filename) : _filename(std::move(filename)) {}

    lazy_open_ofstream& operator<<(auto other) {
        if (!ofs.is_open()) {
            ofs.open(_filename);
        }
        ofs << other;
        return *this;
    }
private:
    std::ofstream ofs;
    std::string _filename;
};

Then use is as

lazy_open_ofstream ofs("file.txt");

// write to ofs or not

Note: you might want to adjust the operator<< to your needs.