mkdir if not exists using golang
Asked Answered
E

7

157

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");
Electret answered 20/6, 2016 at 22:3 Comment(0)
G
199

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)
    
Grouse answered 20/6, 2016 at 22:13 Comment(9)
For anyone wondering what the variable mode is, see: golang.org/pkg/os/#FileMode. You probably want to use os.ModeDir as its value.Arginine
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 for more details.Crevice
Why do we ignore any issues when we do os.Mkdir() ?Insole
@Insole It will error if it already exists, which is okay. Probably not recommended though.Aurelioaurelius
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.Indign
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?Cortezcortical
@Giannis, @472084: There are other reasons os.Mkdir() can return a non-nil error too. So the error should absolutely be checked.Contingent
https://mcmap.net/q/150851/-mkdir-if-not-exists-using-golang is arguably a better answer that doesn't have the issues in this answer.Contingent
With the caveat that it creates parent directories even if that's not intended. The question specifically asks for mkdir not mkdir -p. ¯_(ツ)_/¯Grouse
E
247

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.

Electret answered 20/6, 2016 at 22:13 Comment(2)
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.Optimism
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.") } `Unlade
G
199

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)
    
Grouse answered 20/6, 2016 at 22:13 Comment(9)
For anyone wondering what the variable mode is, see: golang.org/pkg/os/#FileMode. You probably want to use os.ModeDir as its value.Arginine
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 for more details.Crevice
Why do we ignore any issues when we do os.Mkdir() ?Insole
@Insole It will error if it already exists, which is okay. Probably not recommended though.Aurelioaurelius
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.Indign
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?Cortezcortical
@Giannis, @472084: There are other reasons os.Mkdir() can return a non-nil error too. So the error should absolutely be checked.Contingent
https://mcmap.net/q/150851/-mkdir-if-not-exists-using-golang is arguably a better answer that doesn't have the issues in this answer.Contingent
With the caveat that it creates parent directories even if that's not intended. The question specifically asks for mkdir not mkdir -p. ¯_(ツ)_/¯Grouse
E
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  
}
Erastes answered 14/6, 2019 at 14:54 Comment(3)
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.Cymbiform
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).Contingent
I've addressed the issue described in my earlier comment in an edit to this answer.Contingent
R
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.

Rusert answered 15/7, 2020 at 0:34 Comment(0)
G
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)
}
Great answered 12/12, 2020 at 8:32 Comment(1)
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).Contingent
T
1

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.")
    }
}
Tailpipe answered 21/7, 2023 at 17:15 Comment(0)
P
1

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

Powers answered 14/8, 2023 at 13:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.