¿Cómo crear directorios anidados usando Mkdir en Golang?

95

Estoy tratando de crear un conjunto de directorios anidados a partir de un ejecutable de Go como 'dir1 / dir2 / dir3'. He logrado crear un solo directorio con esta línea:

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

Sin embargo, no tengo idea de cómo abordar la creación de un conjunto anidado predeterminado de directorios dentro de ese directorio.

tommymcdonald
fuente

Respuestas:

176

os.Mkdirse utiliza para crear un único directorio. Para crear una ruta de carpeta, intente usar:

os.MkdirAll(folderPath, os.ModePerm)

Ir documentación

func MkdirAll (cadena de ruta, perm FileMode) error

MkdirAll crea un directorio llamado ruta, junto con los padres necesarios, y devuelve nil o devuelve un error. Los bits de permiso perm se utilizan para todos los directorios que crea MkdirAll. Si la ruta ya es un directorio, MkdirAll no hace nada y devuelve nil.

Editar:

Actualizado para usarlo correctamente en su os.ModePermlugar.
Para la concatenación de rutas de archivo, use el paquete path/filepathcomo se describe en la respuesta de @Chris.

ANiso
fuente
@CodeWarrior: Gracias por el ping. Actualicé mi respuesta y voté a favor de Chris
ANisus
¡Gracias @chris! :)
Thales P
1
Es posible que desee elegir entre 0755y os.ModePerm.
updogliu
102

De esta forma no tienes que usar ningún número mágico:

os.MkdirAll(newPath, os.ModePerm)

Además, en lugar de usar + para crear rutas, puede usar:

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

Lo anterior utiliza automáticamente los separadores correctos en cada plataforma.

Chris
fuente
2
Esta es la respuesta correcta. Mucho más simple y agnóstico de plataforma.
Dan Esparza
6

Si el problema es crear todos los directorios principales necesarios, podría considerar usar os.MkDirAll()

MkdirAll crea un directorio llamado ruta, junto con los padres necesarios, y devuelve nil, o devuelve un error.

El path_test.go es un buen ejemplo de cómo se usa:

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_")
...
}

(Asegúrese de especificar un valor de permiso razonable, como se menciona en esta respuesta )

VonC
fuente
3

Se puede utilizar un método de utilidad como el siguiente para resolver esto.

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.")
}
skipy
fuente
1

Esta es una alternativa para lograr lo mismo, pero evita la condición de carrera causada por tener dos operaciones distintas "comprobar ... y ... crear".

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
    }
}
pr-pal
fuente