Comment créer des répertoires imbriqués en utilisant Mkdir dans Golang?

95

J'essaie de créer un ensemble de répertoires imbriqués à partir d'un exécutable Go tel que «dir1 / dir2 / dir3». J'ai réussi à créer un répertoire unique avec cette ligne:

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

Cependant, je n'ai aucune idée de comment aborder la création d'un ensemble imbriqué prédéterminé de répertoires à l'intérieur de ce répertoire.

tommymcdonald
la source

Réponses:

176

os.Mkdirest utilisé pour créer un répertoire unique. Pour créer un chemin de dossier, essayez plutôt d'utiliser:

os.MkdirAll(folderPath, os.ModePerm)

Aller à la documentation

erreur func MkdirAll (chaîne de chemin, perm FileMode)

MkdirAll crée un répertoire nommé chemin, avec tous les parents nécessaires, et renvoie nil, ou renvoie une erreur. Les bits d'autorisation perm sont utilisés pour tous les répertoires créés par MkdirAll. Si path est déjà un répertoire, MkdirAll ne fait rien et renvoie nil.

Éditer:

Mis à jour pour utiliser correctement à la os.ModePermplace.
Pour la concaténation des chemins de fichiers, utilisez package path/filepathcomme décrit dans la réponse de @Chris.

ANisus
la source
@CodeWarrior: Merci pour le ping. J'ai mis à jour ma réponse et j'ai voté pour Chris
ANisus
Merci @chris! :)
Thales P
1
Vous pouvez choisir entre 0755et os.ModePerm.
updogliu
102

De cette façon, vous n'avez pas besoin d'utiliser de nombres magiques:

os.MkdirAll(newPath, os.ModePerm)

De plus, plutôt que d'utiliser + pour créer des chemins, vous pouvez utiliser:

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

Ce qui précède utilise automatiquement les bons séparateurs sur chaque plate-forme pour vous.

Chris
la source
2
C'est la bonne réponse. Beaucoup plus simple et indépendant de la plate-forme.
Dan Esparza
6

Si le problème est de créer tous les répertoires parents nécessaires, vous pouvez envisager d'utiliser os.MkDirAll()

MkdirAll crée un répertoire nommé chemin, avec tous les parents nécessaires, et renvoie nil, ou renvoie une erreur.

Le path_test.go est une bonne illustration de son utilisation:

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

(Assurez-vous de spécifier une valeur d'autorisation raisonnable, comme mentionné dans cette réponse )

VonC
la source
3

Une méthode utilitaire telle que la suivante peut être utilisée pour résoudre ce problème.

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
la source
1

Ceci est une alternative pour obtenir la même chose mais cela évite la condition de concurrence causée par deux opérations distinctes "vérifier .. et .. créer".

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
la source