148

I am learning golang(beginner) and I have been searching on both google and stackoverflow but I could not find an answer so excuse me if already asked, but how can I mkdir if not exists in golang.

For example in node I would use fs-extra with the function ensureDirSync (if blocking is of no concern of course)

fs.ensureDir("./public");
stacker-baka
  • 333
  • 6
  • 12
Alfred
  • 60,935
  • 33
  • 147
  • 186

7 Answers7

233

Okay I figured it out thanks to this question/answer

import(
    "os"
    "path/filepath"
)

newpath := filepath.Join(".", "public")
err := os.MkdirAll(newpath, os.ModePerm)
// TODO: handle error

Relevant Go doc for MkdirAll:

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

...

If path is already a directory, MkdirAll does nothing and returns nil.

nishanthshanmugham
  • 2,967
  • 1
  • 25
  • 29
Alfred
  • 60,935
  • 33
  • 147
  • 186
  • 9
    This is the best answer, and is using the stdlib. This is especially useful when used alongside os.Create, where you might need to create sub-dirs as well (using `filepath.Dir("path/to/file")` on the complete path to the file is a nice approach in my eyes. – Paddie Oct 03 '16 at 14:56
  • 6
    You might want to check for any error response on the MkdirAll call like: ` if err := os.MkdirAll("/somepath/", os.ModeDir); err != nil { fmt.Println("Cannot create hidden directory.") } ` – Paul A. Fortin Jun 04 '17 at 11:17
194

I've ran across two ways:

  1. Check for the directory's existence and create it if it doesn't exist:

    if _, err := os.Stat(path); os.IsNotExist(err) {
        err := os.Mkdir(path, mode)
        // TODO: handle error
    }
    

However, this is susceptible to a race condition: the path may be created by someone else between the os.Stat call and the os.Mkdir call.

  1. Attempt to create the directory and ignore any issues (ignoring the error is not recommended):

    _ = os.Mkdir(path, mode)
    
nishanthshanmugham
  • 2,967
  • 1
  • 25
  • 29
Austin Hanson
  • 21,820
  • 6
  • 35
  • 41
  • 57
    For anyone wondering what the variable `mode` is, see: https://golang.org/pkg/os/#FileMode. You probably want to use `os.ModeDir` as its value. – The Unknown Dev Jun 03 '19 at 16:27
  • 9
    Also for those wondering about the `mode`, you could use `os.Mkdir("dirname", 0700)` if you want to be able to write into that directory from the same program, see [this](https://stackoverflow.com/questions/14249467/os-mkdir-and-os-mkdirall-permission-value/31151508) for more details. – Jairo Lozano Dec 21 '19 at 00:12
  • 5
    Why do we ignore any issues when we do os.Mkdir() ? – Giannis Jun 22 '20 at 11:27
  • 1
    @Giannis It will error if it already exists, which is okay. Probably not recommended though. – 472084 Aug 26 '20 at 12:59
  • 8
    When creating a directory to store files in the mode `os.ModeDir`. The new directory does not have enough permissions. I found only `os.ModePerm` worked for me. Which is equivalent to `0777` or `drwxr-xr-x`. I think the permissions can be a bit lower but `0666` did not do the trick. – Justin Oct 22 '20 at 06:56
  • 3
    Wouldn't option 1 be susceptible to a race condition if someone else creates the directory in between you checking if exists and then creating it? – sgonzalez Dec 03 '20 at 21:27
  • @Giannis, @472084: There are other reasons `os.Mkdir()` can return a non-nil error too. So the error should absolutely be checked. – nishanthshanmugham Jun 01 '21 at 22:31
  • https://stackoverflow.com/a/37932672/3309046 is arguably a better answer that doesn't have the issues in this answer. – nishanthshanmugham Jun 01 '21 at 22:37
  • With the caveat that it creates parent directories even if that's not intended. The question specifically asks for `mkdir` not `mkdir -p`. ¯\_(ツ)_/¯ – Austin Hanson Jun 02 '21 at 12:33
9

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.Mkdir(dirName, os.ModeDir)
    if err == nil {
        return nil
    }
    if os.IsExist(err) {
        // check that the existing path is a directory
        info, err := os.Stat(dirName)
        if err != nil {
            return err
        }
        if !info.IsDir() {
            return errors.New("path exists but is not a directory")
        }
        return nil
    }
    return err  
}
nishanthshanmugham
  • 2,967
  • 1
  • 25
  • 29
pr-pal
  • 3,248
  • 26
  • 18
  • While your code may provide the answer to the question, please add context around it so others will have some idea what it does and why it is there. – Theo Jun 14 '19 at 18:45
  • 2
    This answer is partially incorrect. The `os.IsExist(err)` check in `ensureDir` is not sufficient: the existing path may not necessarily be a directory. So `ensureDir` will return a nil error but ultimately the item at the path may not be a directory (it may be a reguar file, for instance). – nishanthshanmugham Jun 01 '21 at 22:40
  • I've addressed the issue described in my earlier comment in an edit to this answer. – nishanthshanmugham Jun 01 '21 at 22:46
4

So what I have found to work for me is:

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

//Get the cur file dir
path, err := filepath.Abs("./") // current opened dir (NOT runner dir)

// If you want runner/executable/binary file dir use `_, callerFile, _, _ := runtime.Caller(0)
// path := filepath.Dir(callerFile)`
if err != nil {
    log.Println("error msg", err)
}

//Create output path
outPath := filepath.Join(path, "output")

//Create dir output using above code
if _, err = os.Stat(outPath); os.IsNotExist(err) {
    var dirMod uint64
    if dirMod, err = strconv.ParseUint("0775", 8, 32); err == nil {
        err = os.Mkdir(outPath, os.FileMode(dirMod))
    }
}
if err != nil && !os.IsExist(err)  {
    log.Println("error msg", err)
}

I like the portability of this.

madzohan
  • 11,488
  • 9
  • 40
  • 67
just_myles
  • 235
  • 2
  • 9
1

Or you could attempt creating the file and check that the error returned isn't a "file exists" error

if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) {
    log.Fatal(err)
}
  • This answer is partially incorrect. Particularly the `!os.IsExist(err)` check is incorrect. The existing path may not necessarily be a directory. So ultimately the code will continue onward (i.e. `log.Fatal` won't be executed), but `path` may not be a directory (it may be a reguar file, for instance). – nishanthshanmugham Jun 01 '21 at 22:49
0

To create a directory if it does not exist, you can follow these steps:

Import the "os" package at the beginning of your Go program. Use the "os.Mkdir()" function to create the directory.

package main

import (
    "fmt"
    "os"
)

func main() {
    // Specify the path of the directory you want to create
    directoryPath := "./my_directory"

    // Check if the directory already exists
    if _, err := os.Stat(directoryPath); os.IsNotExist(err) {
        // The directory does not exist, so create it using os.MkdirAll()
        err := os.MkdirAll(directoryPath, 0755) // 0755 sets the permissions for the directory
        if err != nil {
            fmt.Println("Error creating directory:", err)
            return
        }
        fmt.Println("Directory created successfully.")
    } else {
        fmt.Println("Directory already exists.")
    }
}
Prashant Luhar
  • 299
  • 5
  • 19
0

you can use this for making new directory in golang:

package main

import (
    "fmt"
    "os"
)

func main() {
    // Specify the directory path you want to create
    dirPath := "my_directory"

    // Create the directory with the specified path
    err := os.Mkdir(dirPath, 0755) // 0755 sets permissions for the directory
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    fmt.Println("Directory created:", dirPath)
}

I hope it will be helpful for you

Md Kamruzzaman
  • 346
  • 1
  • 8