4

As mentioned in GoDocs, os.Create() creates a file in specific path.

os.Create("fonts/foo/font.eot")

But when fonts or foo doesn't exists, it returns panic: open fonts/foo/font.eot: The system cannot find the path specified.
So i used os.MkdirAll() to create nested directory. But there are many other problems with this function.

path := "fonts/foo/font.eot"
// this line create a directory named (font.eot) !
os.MkdirAll(path, os.ModePerm)

Is there any better way to create a file in nested directories?

Exind
  • 417
  • 1
  • 6
  • 12
  • 3
    That's the proper way to do such things - on the system level those map to `mkdir` and `open` system calls. What "many other problems" are you referring to? – oakad Jan 29 '20 at 06:26
  • 4
    It is `os.MkdirAll("fonts/foo", 0770); os.Create("fonts/foo/font.eot")` Dead simple and totaly obvious. – Volker Jan 29 '20 at 06:29
  • 1
    @Volker: most programs should probably use mode `0777` rather than `0770` here. File creation generally should use mode `0666`. These allow the user's umask to take away group and/or other write permissions if desired, or even more permissions (resulting in modes like 0750 or 0700 for a directory) if desired. (I've seen this advice to use 0770 elsewhere, but am not sure where it originates.) – torek Jan 29 '20 at 08:17
  • 4
    @torek Neither the filepaths nor the modes are fixed and need adoption to your particular use case. There is no single correct value. – Volker Jan 29 '20 at 10:29

1 Answers1

28

The standard way is something like this:

func create(p string) (*os.File, error) {
    if err := os.MkdirAll(filepath.Dir(p), 0770); err != nil {
        return nil, err
    }
    return os.Create(p)
}

A few notes:

  • os.Create does not panic as stated in the question.
  • Create a directory from the directory part of the file path, not the full path.
stantonJones
  • 296
  • 3
  • 2