Come creare directory annidate usando Mkdir in Golang?


95

Sto cercando di creare una serie di directory nidificate da un eseguibile Go come "dir1 / dir2 / dir3". Sono riuscito a creare una singola directory con questa riga:

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

Tuttavia, non ho idea di come affrontare la creazione di un set di directory annidato predeterminato all'interno di quella directory.

Risposte:


176

os.Mkdirviene utilizzato per creare una singola directory. Per creare un percorso di cartella, prova invece a utilizzare:

os.MkdirAll(folderPath, os.ModePerm)

Vai alla documentazione

func MkdirAll (stringa del percorso, perm FileMode) errore

MkdirAll crea una directory denominata path, insieme a tutti i genitori necessari, e restituisce nil, oppure restituisce un errore. I bit di autorizzazione perm vengono utilizzati per tutte le directory create da MkdirAll. Se path è già una directory, MkdirAll non fa nulla e restituisce nil.

Modificare:

Aggiornato per un uso corretto os.ModePerminvece.
Per la concatenazione dei percorsi dei file, usa il pacchetto path/filepathcome descritto nella risposta di @Chris.


@ CodeWarrior: Grazie per il ping. Ho aggiornato la mia risposta e ho votato positivamente Chris
ANisus il

Grazie @chris! :)
Thales P

1
Puoi scegliere tra 0755e os.ModePerm.
aggiornamento del

102

In questo modo non devi usare numeri magici:

os.MkdirAll(newPath, os.ModePerm)

Inoltre, invece di usare + per creare percorsi, puoi usare:

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

Quanto sopra utilizza automaticamente i separatori corretti su ciascuna piattaforma per te.


2
Questa è la risposta corretta. Molto più semplice e indipendente dalla piattaforma.
Dan Esparza

6

Se il problema è creare tutte le directory principali necessarie, potresti prendere in considerazione l'utilizzo di os.MkDirAll()

MkdirAll crea una directory denominata path, insieme a tutti i genitori necessari, e restituisce zero, oppure restituisce un errore.

Il path_test.go è una buona illustrazione su come usarlo:

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

(Assicurati di specificare un valore di autorizzazione ragionevole, come menzionato in questa risposta )


3

Un metodo di utilità come il seguente può essere utilizzato per risolvere questo problema.

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

1

Questa è un'alternativa per ottenere lo stesso risultato, ma evita la condizione di competizione causata dall'avere due distinte operazioni di "verifica ... e ... creazione".

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
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.