Jak tworzyć zagnieżdżone katalogi za pomocą Mkdir w Golang?

97

Próbuję utworzyć zestaw zagnieżdżonych katalogów z pliku wykonywalnego Go, takiego jak „dir1 / dir2 / dir3”. Udało mi się stworzyć pojedynczy katalog z tą linią:

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

Jednak nie mam pojęcia, jak podejść do tworzenia z góry określonego zagnieżdżonego zestawu katalogów w tym katalogu.

tommymcdonald
źródło

Odpowiedzi:

182

os.Mkdirsłuży do tworzenia pojedynczego katalogu. Aby utworzyć ścieżkę do folderu, spróbuj użyć:

os.MkdirAll(folderPath, os.ModePerm)

Przejdź do dokumentacji

func MkdirAll (ciąg ścieżki, perm FileMode)

MkdirAll tworzy katalog o nazwie path wraz ze wszystkimi niezbędnymi elementami nadrzędnymi i zwraca wartość nil lub zwraca błąd. Bity uprawnień są używane dla wszystkich katalogów, które tworzy MkdirAll. Jeśli ścieżka jest już katalogiem, MkdirAll nic nie robi i zwraca nil.

Edytować:

Zaktualizowano, aby os.ModePermzamiast tego poprawnie używać .
Aby path/filepathpołączyć ścieżki plików, użyj pakietu, jak opisano w odpowiedzi @Chris.

ANisus
źródło
@CodeWarrior: Dzięki za ping. Zaktualizowałem swoją odpowiedź i zagłosowałem za Chrisem
ANisusem
Dziękuję @chris! :)
Thales P
1
Możesz wybrać między 0755i os.ModePerm.
updogliu
103

W ten sposób nie musisz używać żadnych magicznych liczb:

os.MkdirAll(newPath, os.ModePerm)

Zamiast używać + do tworzenia ścieżek, możesz użyć:

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

Powyższe automatycznie używa poprawnych separatorów na każdej platformie.

Chris
źródło
3
To jest poprawna odpowiedź. Znacznie prostsze i niezależne od platformy.
Dan Esparza
6

Jeśli problemem jest utworzenie wszystkich niezbędnych katalogów nadrzędnych, możesz rozważyć użycie os.MkDirAll()

MkdirAll tworzy katalog o nazwie path, wraz z wszelkimi niezbędnymi rodzicami i zwraca nil lub zwraca błąd.

Path_test.go jest dobrym przykładem tego, jak z niego korzystać:

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

(Upewnij się, że podałeś rozsądną wartość pozwolenia, jak wspomniano w tej odpowiedzi )

VonC
źródło
3

Aby rozwiązać ten problem, można użyć metody narzędziowej, takiej jak poniższa.

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
źródło
1

Jest to jedna z możliwości osiągnięcia tego samego, ale pozwala uniknąć sytuacji wyścigu spowodowanej dwoma różnymi operacjami „sprawdź .. i… utwórz”.

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
źródło