std::ofstream, check if file exists before writing
Asked Answered
H

6

38

I am implementing file saving functionality within a Qt application using C++.

I am looking for a way to check to see if the selected file already exists before writing to it, so that I can prompt a warning to the user.

I am using an std::ofstream and I am not looking for a Boost solution.

Hyonhyoscine answered 30/11, 2010 at 17:11 Comment(2)
Possible duplicate questions: #1384117, #574785, #268523Shanaeshanahan
add a dup: #12774707Collinear
I
71

This is one of my favorite tuck-away functions I keep on hand for multiple uses.

#include <sys/stat.h>
// Function: fileExists
/**
 *  Check if a file exists
 *
 * @param[in] filename - the name of the file to check
 *
 * @return    true if the file exists, else false
*/
bool fileExists(const std::string& filename)
{
    struct stat buf;
    if (stat(filename.c_str(), &buf) != -1)
    {
        return true;
    }
    return false;
}

I find this much more tasteful than trying to open a file if you have no immediate intentions of using it for I/O.

Israel answered 9/6, 2011 at 17:24 Comment(7)
+1 for an example using stat instead of opening a file just to close it.Simile
+1 but return stat(filename.c_str(), &buf) != 1; is rather more compact.Glia
I timed these on a 2.67GHz Intel Xeon. The stat method above took 0.93 microseconds to confirm that a 500MB file existed. The ifstream methods below took 17.4 microseconds on the same file. To tell that no file exists, stat took 0.72 microseconds, ifstream took 2.4 microseconds.Muff
@MattPhillips: But that doesn't seem to have the desired effect.Maelstrom
@Steve: Apart from the fact that Matt Phillips' code didn't declare the struct (I assume he meant it to be implied), and the fact that he used != 1 rather than != -1, why wouldn't it have the same effect?Minne
I think he meant bool fileExists(const std::string& filename) { struct stat buf; return (stat(filename.c_str(), &buf) != -1); }Edgy
Is there a reason for the use of the struct keyword? It's not necessary in C++, unless there is some name conflict inside the C header that I'm not aware of?Latter
L
42
bool fileExists(const char *fileName)
{
    ifstream infile(fileName);
    return infile.good();
}

This method is so far the shortest and most portable one. If the usage is not very sophisticated, this is one I would go for. If you also want to prompt a warning, I would do that in the main.

Lauraine answered 15/6, 2012 at 18:41 Comment(2)
Explanation: Uses the ifstream constructor to attempt to open the file for reading. When the function returns and the ifstream goes out of scope its destructor will implicitly close the file (in the event that the file existed and the open succeeded).Upanishad
Except that it does the wrong thing: it checks if a file can be opened, not if it exists. If access permissions disallow the user to access it, this function will erroneously claim that the file does not exist, because it will be unable to open it for reading.Tullusus
D
10
fstream file;
file.open("my_file.txt", ios_base::out | ios_base::in);  // will not create file
if (file.is_open())
{
    cout << "Warning, file already exists, proceed?";
    if (no)
    { 
        file.close();
        // throw something
    }
}
else
{
    file.clear();
    file.open("my_file.txt", ios_base::out);  // will create if necessary
}

// do stuff with file

Note that in case of an existing file, this will open it in random-access mode. If you prefer, you can close it and reopen it in append mode or truncate mode.

Distich answered 9/6, 2011 at 18:34 Comment(4)
Think on what would happen if the file exists, but the user doesn't have access permissions to read it.Tullusus
@SasQ: Yeah... this is definitely a hack / workaround. The proper solution in C++17 is std::filesystem::exists(), or barring that, stat().Distich
@Distich “ barring that, stat()”? What's that? What do you intend to tell us?Stonedead
@Stonedead If your standard library implementation does not support std::filesystem yet, you can use the stat() function from the POSIX API (also supported on Windows)Distich
S
6

With std::filesystem::exists of C++17:

#include <filesystem> // C++17
#include <iostream>
namespace fs = std::filesystem;

int main()
{
    fs::path filePath("path/to/my/file.ext");
    std::error_code ec; // For using the noexcept overload.
    if (!fs::exists(filePath, ec) && !ec)
    {
        // Save to file, e.g. with std::ofstream file(filePath);
    }
    else
    {
        if (ec)
        {
            std::cerr << ec.message(); // Replace with your error handling.
        }
        else
        {
            std::cout << "File " << filePath << " does already exist.";
            // Handle overwrite case.
        }
    }
}

See also std::error_code.

In case you want to check if the path you are writing to is actually a regular file, use std::filesystem::is_regular_file.

Sogdian answered 18/6, 2018 at 17:19 Comment(0)
M
5

Try ::stat() (declared in <sys/stat.h>)

Moonshine answered 30/11, 2010 at 17:13 Comment(0)
B
2

One of the way would be to do stat() and check on errno.
A sample code would look look this:

#include <sys/stat.h>
using namespace std;
// some lines of code...

int fileExist(const string &filePath) {
    struct stat statBuff;
    if (stat(filePath.c_str(), &statBuff) < 0) {
        if (errno == ENOENT) return -ENOENT;
    }
    else
        // do stuff with file
}

This works irrespective of the stream. If you still prefer to check using ofstream just check using is_open().
Example:

ofstream fp.open("<path-to-file>", ofstream::out);
if (!fp.is_open()) 
    return false;
else 
    // do stuff with file

Hope this helps. Thanks!

Brisco answered 30/7, 2016 at 10:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.