169

I want to check the existence of file ./conf/app.ini in my Go code, but I can't find a good way to do that.

I know there is a method of File in Java: public boolean exists(), which returns true if the file or directory exists.

But how can this be done in Go?

hardPass
  • 19,033
  • 19
  • 40
  • 42
  • 9
    Also note that depending on how you're going to use this information you've got a race condition. All you can say is that a little while ago the file did/did-not exist; by the time you act on the test the opposite may be true. Usually it's much better to check while doing whatever operation you intend to do (e.g. don't check before opening an existing or creating a new file but do `f, err := os.Open(name)` or `f, err := os.OpenFile(name,os.O_CREATE|os.O_EXCL, mode)` and then check `os.IsNotExist(err)`). – Dave C Jun 08 '15 at 14:30

6 Answers6

255
// exists returns whether the given file or directory exists
func exists(path string) (bool, error) {
    _, err := os.Stat(path)
    if err == nil { return true, nil }
    if os.IsNotExist(err) { return false, nil }
    return false, err
}

Edited to add error handling.

vercetti
  • 55
  • 1
  • 8
Mostafa
  • 26,886
  • 10
  • 57
  • 52
  • 5
    It looks like 'exception programming' to me. Is there any resource that justify this kind of code as an official #golang paradigm? – Olivier Amblet Nov 23 '12 at 22:03
  • @OlivierAmblet Sorry for the late response. What do you mean by “this kind of code”? Checking for `err` or what? – Mostafa Mar 15 '13 at 19:15
  • 26
    @OlivierAmblet There is no exception happening here. Go uses `panic` for an actual "exception" like object. You can "catch" with a call to `recover`. Explicitly returning an `err` as a second return value is an extremely common, idiomatic Go technique. See: http://golang.org/doc/effective_go.html#errors – Chris Pfohl Aug 13 '13 at 20:19
  • 14
    the solution is not very straitforward, go is special – zhaozhi Jan 17 '14 at 06:34
  • 1
    It's true that there is no boolean Exists function, but the application code can be simpler if you only want to check for the existence of a file: `if _, err := os.Stat("./conf/app.ini"); err == nil { /*exists*/ } else { /*not exists or some other error*/ }` – Tobia Sep 11 '14 at 08:50
  • 21
    Why is everything in this language so complicated? – Top Cat May 31 '18 at 09:18
  • 1
    Most Go APIs are not this complex. This is an exception. The problem is that the filesystem overloads the concept of an "error" to include both "file not found" and "omg, there was a real filesystem problem!". The code has to figure out which it is. Go provides `os.IsNotExist(err)` to disambiguate. – TomOnTime Jun 06 '20 at 19:30
  • Shouldn't this check `os.IsNotExist(err)` before checking if the error is nil? Check the special case before the general case – Ben Oct 21 '20 at 20:22
  • 4
    The new style is to use the `errors` package `if errors.Is(err, os.ErrNotExist) { /* handle not exists */ }` – Alexander Günther Apr 01 '21 at 06:12
  • "Why is everything in this language so complicated?" Because many other languages / their standard libraries just don't provide this level of clarity and control. – nishanthshanmugham Feb 04 '22 at 22:06
  • 1
    @Ben "Shouldn't this check os.IsNotExist(err) before checking if the error is nil?" The two scenarios are mutually exclusive, so order should not matter. If the err == nil, then err definitely cannot satisfy `os.IsNotExist`, and vice versa. If we were talking about checking err != nil (which isn't the case here) then order would matter. – nishanthshanmugham Feb 04 '22 at 22:08
  • @AlexanderGünther, I fully agree that `errors.Is(err, os.ErrNotExist)` is the better approach, but it isn't only a matter of style. The `Is()` function also checks whether one of the wrapped errors is a `os.ErrNotExist` error, therefore is much safer and strongly recommended. – MaBekitsur Nov 13 '22 at 18:12
144

You can use this :

if _, err := os.Stat("./conf/app.ini"); err != nil {
    if os.IsNotExist(err) {
        // file does not exist
    } else {
        // other error
    }
}

See : http://golang.org/pkg/os/#IsNotExist

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
37

More of an FYI, since I looked around for a few minutes thinking my question be a quick search away.

How to check if path represents an existing directory in Go?

This was the most popular answer in my search results, but here and elsewhere the solutions only provide existence check. To check if path represents an existing directory, I found I could easily:

path := GetSomePath();
if stat, err := os.Stat(path); err == nil && stat.IsDir() {
    // path is a directory
}

Part of my problem was that I expected path/filepath package to contain the isDir() function.

Edward Wagner
  • 479
  • 4
  • 5
19

Simple way to check whether file exists or not:

if _, err := os.Stat("/path/to/whatever"); os.IsNotExist(err) {
    // path/to/whatever does not exist
}

if _, err := os.Stat("/path/to/whatever"); err == nil {
    // path/to/whatever exists
}

Sources:

Cœur
  • 37,241
  • 25
  • 195
  • 267
Nikta Jn
  • 346
  • 3
  • 7
  • If I told you "Simple way to get rich quick: put money in bank. take money from bank." you would think I was telling you that there were two serial steps required rather than two alternative steps. The problem with this answer is that readers may not understand that you are suggesting two different possible approaches. – kfsone Sep 08 '20 at 22:34
1

I use the following function to check my directories for any errors. It's very similar to previous answers, but I think not nesting ifs makes the code more clear. It uses go-homedir to remove ~ from directory paths and pkg/errors to return nicer error messages, but it would be easy to take them out if you don't need their functionality.

// validateDirectory expands a directory and checks that it exists
// it returns the full path to the directory on success
// validateDirectory("~/foo") -> ("/home/bbkane/foo", nil)
func validateDirectory(dir string) (string, error) {
    dirPath, err := homedir.Expand(dir)
    if err != nil {
        return "", errors.WithStack(err)
    }
    info, err := os.Stat(dirPath)
    if os.IsNotExist(err) {
        return "", errors.Wrapf(err, "Directory does not exist: %v\n", dirPath)
    }
    if err != nil {
        return "", errors.Wrapf(err, "Directory error: %v\n", dirPath)

    }
    if !info.IsDir() {
        return "", errors.Errorf("Directory is a file, not a directory: %#v\n", dirPath)
    }
    return dirPath, nil
}

Also, to repeat @Dave C's comment, if the reason you're checking a directory's existence is to write a file into it, it's usually better to simply try to open it an deal with errors afterwards:

// O_EXCL - used with O_CREATE, file must not exist
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
    return errors.WithStack(err)
}
defer file.Close()
Ben
  • 5,952
  • 4
  • 33
  • 44
-4

There is simple way to check whether your file exists or not:

if _, err := os.Stat("./conf/app.ini"); err != nil {
    if os.IsNotExist(err) {
        ..... //Shows error if file not exists
    } else {
       ..... // Shows success message like file is there
    }
}
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Kabeer Shaikh
  • 207
  • 3
  • 2