Como criar diretórios aninhados usando Mkdir no Golang?

95

Estou tentando criar um conjunto de diretórios aninhados de um executável Go, como 'dir1 / dir2 / dir3'. Consegui criar um único diretório com esta linha:

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

No entanto, não tenho ideia de como criar um conjunto predeterminado de diretórios aninhados dentro desse diretório.

tommymcdonald
fonte

Respostas:

176

os.Mkdiré usado para criar um único diretório. Para criar um caminho de pasta, tente usar:

os.MkdirAll(folderPath, os.ModePerm)

Documentação Go

função MkdirAll (path string, perm FileMode) error

MkdirAll cria um diretório chamado path, junto com todos os pais necessários, e retorna nil, ou então retorna um erro. Os bits de permissão perm são usados ​​para todos os diretórios que MkdirAll cria. Se o caminho já for um diretório, MkdirAll não faz nada e retorna nil.

Editar:

Atualizado para usar corretamente os.ModePerm.
Para concatenação de caminhos de arquivo, use o pacote path/filepathconforme descrito na resposta de @Chris.

ANisus
fonte
@CodeWarrior: Obrigado pelo ping. Eu atualizei minha resposta e votei contra Chris
ANisus
Obrigado @chris! :)
Thales P
1
Você pode querer escolher entre 0755 e os.ModePerm.
updogliu
102

Dessa forma, você não precisa usar nenhum número mágico:

os.MkdirAll(newPath, os.ModePerm)

Além disso, em vez de usar + para criar caminhos, você pode usar:

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

O acima usa os separadores corretos automaticamente em cada plataforma para você.

Chris
fonte
2
Essa é a resposta correta. Muito mais simples e independente de plataforma.
Dan Esparza
6

Se o problema for criar todos os diretórios pais necessários, você pode considerar o uso os.MkDirAll()

MkdirAll cria um diretório denominado path, junto com todos os pais necessários e retorna nil ou então retorna um erro.

O path_test.go é uma boa ilustração de como usá-lo:

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

(Certifique-se de especificar um valor de permissão razoável, conforme mencionado nesta resposta )

VonC
fonte
3

Um método utilitário como o seguinte pode ser usado para resolver isso.

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.")
}
saltitante
fonte
1

Esta é uma alternativa para obter o mesmo, mas evita a condição de corrida causada por ter duas operações distintas de "verificar .. e .. criar".

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
fonte