How to create nested directories using Mkdir in Golang?
Asked Answered
M

5

138

I am trying to create a set of nested directories from a Go executable such as 'dir1/dir2/dir3'. I have succeeded in creating a single directory with this line:

os.Mkdir("." + string(filepath.Separator) + c.Args().First(),0777);

However, I have no idea how to approach creating a predetermined nested set of directories inside of that directory.

Manzanares answered 11/2, 2015 at 7:15 Comment(0)
B
267

os.Mkdir is used to create a single directory. To create a folder path, instead try using:

os.MkdirAll(folderPath, os.ModePerm)

Go documentation

func MkdirAll(path string, perm FileMode) error

MkdirAll creates a directory named path, along with any necessary parents, and returns nil, or else returns an error. The permission bits perm are used for all directories that MkdirAll creates. If path is already a directory, MkdirAll does nothing and returns nil.

Edit:

Updated to correctly use os.ModePerm instead.
For concatenation of file paths, use package path/filepath as described in @Chris' answer.

Beffrey answered 11/2, 2015 at 7:25 Comment(1)
You may want to choose between 0755 and os.ModePerm.Israel
P
128

This way you don't have to use any magic numbers:

os.MkdirAll(newPath, os.ModePerm)

Also, rather than using + to create paths, you can use:

import "path/filepath"
path := filepath.Join(someRootPath, someSubPath)

The above uses the correct separators automatically on each platform for you.

Prognostication answered 24/12, 2015 at 10:52 Comment(0)
S
10

This is one alternative for achieving the same but it avoids race condition caused by having two distinct "check ..and.. create" operations.

package main

import (
    "fmt"
    "os"
)

func main()  {
    if err := ensureDir("/test-dir"); err != nil {
        fmt.Println("Directory creation failed with error: " + err.Error())
        os.Exit(1)
    }
    // Proceed forward
}

func ensureDir(dirName string) error {

    err := os.MkdirAll(dirName, os.ModeDir)

    if err == nil || os.IsExist(err) {
        return nil
    } else {
        return err
    }
}
Stour answered 15/6, 2019 at 4:34 Comment(1)
MkdirAll: "If path is already a directory, MkdirAll does nothing and returns nil.", so there's no need to check IsExist errorKrys
D
9

If the issue is to create all the necessary parent directories, you could consider using os.MkDirAll()

MkdirAll creates a directory named path, along with any necessary parents, and returns nil, or else returns an error.

The path_test.go is a good illustration on how to use it:

func TestMkdirAll(t *testing.T) {
    tmpDir := TempDir()
    path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
    err := MkdirAll(path, 0777)
    if err != nil {
    t.Fatalf("MkdirAll %q: %s", path, err)
    }
    defer RemoveAll(tmpDir + "/_TestMkdirAll_")
...
}

(Make sure to specify a sensible permission value, as mentioned in this answer)

Destroyer answered 11/2, 2015 at 7:26 Comment(0)
C
8

An utility method like the following can be used to solve this.

import (
  "os"
  "path/filepath"
  "log"
)

func ensureDir(fileName string) {
  dirName := filepath.Dir(fileName)
  if _, serr := os.Stat(dirName); serr != nil {
    merr := os.MkdirAll(dirName, os.ModePerm)
    if merr != nil {
        panic(merr)
    }
  }
}



func main() {
  _, cerr := os.Create("a/b/c/d.txt")
  if cerr != nil {
    log.Fatal("error creating a/b/c", cerr)
  }
  log.Println("created file in a sub-directory.")
}
Clemens answered 2/1, 2019 at 4:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.