0

Edit: The problem wasn't with my c++. The problem was with how I was calling the shared library in GameMaker Studio, which was why it wasn't working.

I'm trying to detect whether a file exists, and I've tried many methods over the internet and none of them seem to work. Here's an example:

double file_exists(char *filename)
{
    std::ifstream infile(filename);
    return infile.good();
}

I assume it will only work with text files. for example, this won't work:

file_exists("/usr/bin/gedit");

...because that is a Linux executable.

I want a means to check whether a file exists regardless of its file type.

On Windows, this can easily be achieved like so:

double file_exists(char* filename)
{
    DWORD fileAtt = GetFileAttributesA(filename);
    if(fileAtt == INVALID_FILE_ATTRIBUTES)
        throw GetLastError();

    return (bool)((fileAtt&FILE_ATTRIBUTE_DIRECTORY) == 0);
}

But I'm on Linux and I need an equivalent of the above snippet that will work on Linux.

genpfault
  • 51,148
  • 11
  • 85
  • 139
  • 4
    [`stat`](http://man7.org/linux/man-pages/man2/stat.2.html) or [`access`](http://man7.org/linux/man-pages/man2/access.2.html) are two POSIX functions that could be used. Or use [Boost filesystem](http://www.boost.org/doc/libs/1_64_0/libs/filesystem/doc/index.htm) or the upcoming [standard filesystem library](http://en.cppreference.com/w/cpp/filesystem). – Some programmer dude Jun 05 '17 at 06:27
  • Also, when opening a file using C++ streams the system doesn't care about its "filetype". A file is a file is a file... A "text" file is just a way of interpreting the contents by the application, the stream itself doesn't really care about the contents. – Some programmer dude Jun 05 '17 at 06:30
  • Your example works fine for `"/usr/bin/gedit"` – Galik Jun 05 '17 at 07:16
  • "I assume it will" well now the next logical step would be to verify your assumption. – n. m. could be an AI Jun 05 '17 at 07:25
  • BTW, why is your function returning `double` instead of `bool`? – rodrigo Jun 05 '17 at 07:25
  • I said "I assume" because I was trying to rationalize why it wasn't working, which I did verify that it wasn't working, otherwise I never would've posted this question. I've also tried stat and access before I posted this question and neither of them returned true even though gedit clearly exists on my machine. I'm making it return a double because this is a GameMaker Studio extension. GameMaker can only read doubles and chars. It won't recognize the function value if it returns a bool. –  Jun 05 '17 at 19:45

2 Answers2

2

In Linux you have the stat() system call:

struct stat st;
int res = stat(filename, &st);
bool exists = res == 0;

If you want more finesse, you can check the errno if res is non-zero:

if (res == 0)
    return true;
if (errno == ENOENT)
    return false;
throw errno; //you're throwing an int, aren't you?

Also, as a bonus, if you want to know if it is a directory or a normal file or a fifo or a socket or a device... you can check the contents of st.st_mode.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 1
    Instead of throwing `errno` directly I suggest you use [`std::system_error`](http://en.cppreference.com/w/cpp/error/system_error) (see e.g. [this old answer of mine](https://stackoverflow.com/a/12171615/440558) for an example). – Some programmer dude Jun 05 '17 at 06:39
  • I usually throw `std::runtime_error(std::strerror(errno));` to get a useful message – Galik Jun 05 '17 at 07:24
  • All that is nice. I was throwing `errno` just because the OP is throwing `GetLastError()` directly. – rodrigo Jun 05 '17 at 07:25
0

If you are on Linux then GCC implements the filesystem Technical Specification, soon to be included in C++17.

You can use std::filesystem::exists.

#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;

int main()
{
    if(fs::exists("/usr/bin/gedit"))
    {
        ...
        // use file here
    }
}
George Green
  • 4,807
  • 5
  • 31
  • 45
Galik
  • 47,303
  • 4
  • 80
  • 117