19

I've been reading and googling all over but I can't seem to find this simple answer.

I have a function that reads a file, but if the files doesn't exists it panics. What I want to do is a function that before reading, checks if the files exists, and if not, it creates an empty file. Here is what I have.

func exists(path string) (bool, error) {
    _, err := os.Stat(path)
    if err == nil {
        return true, nil
    }
    if os.IsNotExist(err) {
        return false, nil
    }
    return true, err
}
Emi
  • 525
  • 1
  • 3
  • 21

3 Answers3

56

Don't try to check the existence first, since you then have a race if the file is created at the same time. You can open the file with the O_CREATE flag to create it if it doesn't exist:

os.OpenFile(name, os.O_RDONLY|os.O_CREATE, 0666)
JimB
  • 104,193
  • 13
  • 262
  • 255
  • Thanks for the quick reply, but how can I set flags to `ioutil.ReadFile(fileName)` ? – Emi Feb 22 '16 at 17:01
  • 1
    @CoppolaEmilio You can't pass flags to ioutil.ReadFile, but you could just use os.OpenFile with ioutil.ReadAll – nussjustin Feb 22 '16 at 17:15
  • 1
    @CoppolaEmilio: you don't. `ioutil.ReadFile` is just a convenience function to call `os.Open` and `iotuil.ReadAll`. If you need more control, you create your own similar function. – JimB Feb 22 '16 at 17:15
  • 2
    Doesn't this leak a file descriptor? – AndreKR Jun 05 '17 at 05:36
  • 2
    Ah, never mind, according to https://stackoverflow.com/a/8595507/476074 they are closed automatically. – AndreKR Jun 05 '17 at 05:40
  • @AndreKR: If you're worried about "leaking" file descriptors, you can't depend on the finalizer because finalizers are never guaranteed to run, but you should be closing the file anyway. Using `os.O_CREATE` to open a file and create it if it doesn't exist has nothing to do with making sure you call "Close" – JimB Sep 14 '17 at 19:05
  • Seems you are right, if there's no memory pressure it might never be GC'd. In that case I think the answer to "how to create an empty file" should include the call to `Close()`. – AndreKR Sep 14 '17 at 19:15
  • Can this be used to create directories? – Ace.C May 14 '18 at 23:56
7

Just trying to improve the excellent accepted answer.

It's a good idea to check for errors and to Close() the opened file, since file descriptors are a limited resource. You can run out of file descriptors much sooner than a GC runs, and on Windows you can run into file sharing violations.

func TouchFile(name string) error {
    file, err := os.OpenFile(name, os.O_RDONLY|os.O_CREATE, 0644)
    if err != nil {
        return err
    }
    return file.Close()
}
Community
  • 1
  • 1
rustyx
  • 80,671
  • 25
  • 200
  • 267
0

The OpenFile function is the best way to do this, but here is another option:

package main
import "os"

func create(name string) (*os.File, error) {
   _, e := os.Stat(name)
   if e == nil { return nil, os.ErrExist }
   return os.Create(name)
}

func main() {
   f, e := create("file.txt")
   if os.IsExist(e) {
      println("Exist")
   } else if e != nil {
      panic(e)
   }
   f.Close()
}

https://golang.org/pkg/os#ErrExist

Zombo
  • 1
  • 62
  • 391
  • 407