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.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
cweston
  • 11,297
  • 19
  • 82
  • 107
  • 1
    Possible duplicate questions: http://stackoverflow.com/questions/1383617/how-to-check-if-a-file-exists-and-is-readable-in-c, http://stackoverflow.com/questions/574285/checking-existence-of-a-txt-file-with-c-code, http://stackoverflow.com/questions/268023/whats-the-best-way-to-check-if-a-file-exists-in-c-cross-platform – Brent Writes Code Nov 30 '10 at 17:18
  • add a dup: http://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c – zhangxaochen Apr 04 '16 at 04:35

6 Answers6

69

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.

Andrumen1
  • 49
  • 1
  • 8
Rico
  • 5,692
  • 8
  • 46
  • 63
  • 3
    +1 for an example using stat instead of opening a file just to close it. – Chris Smith Jun 10 '11 at 15:23
  • 17
    +1 but `return stat(filename.c_str(), &buf) != 1;` is rather more compact. – Matt Phillips Mar 14 '13 at 16:19
  • 8
    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. – Schroeder Apr 02 '13 at 01:56
  • @MattPhillips: But that doesn't seem to have the desired effect. – Steve Nov 26 '13 at 03:14
  • 1
    @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? – Gurgadurgen May 04 '14 at 14:02
  • I think he meant `bool fileExists(const std::string& filename) { struct stat buf; return (stat(filename.c_str(), &buf) != -1); }` – Kong Chun Ho Jan 12 '17 at 09:14
  • 1
    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? – Lightness Races in Orbit Mar 03 '17 at 17:29
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.

return 0
  • 4,226
  • 6
  • 47
  • 72
  • 8
    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). – grubs Jul 02 '14 at 18:49
  • 3
    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. – SasQ Feb 16 '19 at 11:36
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.

HighCommander4
  • 50,428
  • 24
  • 122
  • 194
  • 1
    Think on what would happen if the file exists, but the user doesn't have access permissions to read it. – SasQ Feb 16 '19 at 11:40
  • 1
    @SasQ: Yeah... this is definitely a hack / workaround. The proper solution in C++17 is [`std::filesystem::exists()`](https://en.cppreference.com/w/cpp/filesystem/exists), or barring that, `stat()`. – HighCommander4 Feb 24 '19 at 13:41
  • @HighCommander4 “ barring that, stat()”? What's that? What do you intend to tell us? – John Oct 08 '21 at 12:53
  • 1
    @John If your standard library implementation does not support `std::filesystem` yet, you can use the [`stat()`](https://www.man7.org/linux/man-pages/man2/stat.2.html) function from the POSIX API (also supported on Windows) – HighCommander4 Oct 08 '21 at 17:53
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.

Roi Danton
  • 7,933
  • 6
  • 68
  • 80
5

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

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
NPE
  • 486,780
  • 108
  • 951
  • 1,012
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!

Bhagyesh Dudhediya
  • 1,800
  • 1
  • 13
  • 16