Wie erstelle ich verschachtelte Verzeichnisse mit Mkdir in Golang?

93

Ich versuche, eine Reihe verschachtelter Verzeichnisse aus einer ausführbaren Go-Datei wie 'dir1 / dir2 / dir3' zu erstellen. Es ist mir gelungen, mit dieser Zeile ein einziges Verzeichnis zu erstellen:

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

Ich habe jedoch keine Ahnung, wie ich einen vorgegebenen verschachtelten Satz von Verzeichnissen in diesem Verzeichnis erstellen soll.

tommymcdonald
quelle

Antworten:

171

os.Mkdirwird verwendet, um ein einzelnes Verzeichnis zu erstellen. Verwenden Sie stattdessen Folgendes, um einen Ordnerpfad zu erstellen:

os.MkdirAll(folderPath, os.ModePerm)

Gehen Sie zur Dokumentation

func MkdirAll (Pfadzeichenfolge, perm FileMode) Fehler

MkdirAll erstellt zusammen mit allen erforderlichen übergeordneten Elementen ein Verzeichnis mit dem Namen path und gibt nil oder einen Fehler zurück. Die Berechtigungsbits perm werden für alle Verzeichnisse verwendet, die MkdirAll erstellt. Wenn path bereits ein Verzeichnis ist, führt MkdirAll nichts aus und gibt nil zurück.

Bearbeiten:

Aktualisiert, um os.ModePermstattdessen korrekt zu verwenden .
Verwenden Sie zur Verkettung von Dateipfaden das Paket path/filepathwie in der Antwort von @Chris beschrieben.

ANisus
quelle
@ CodeWarrior: Danke für den Ping. Ich habe meine Antwort aktualisiert und Chris
ANisus
Danke @chris! :)
Thales P
1
Möglicherweise möchten Sie zwischen 0755und wählen os.ModePerm.
updogliu
100

Auf diese Weise müssen Sie keine magischen Zahlen verwenden:

os.MkdirAll(newPath, os.ModePerm)

Anstatt + zum Erstellen von Pfaden zu verwenden, können Sie auch Folgendes verwenden:

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

Das obige verwendet automatisch die richtigen Trennzeichen auf jeder Plattform für Sie.

Chris
quelle
2
Dies ist die richtige Antwort. Viel einfacher und plattformunabhängig.
Dan Esparza
5

Wenn das Problem darin besteht, alle erforderlichen übergeordneten Verzeichnisse zu erstellen, können Sie die Verwendung in Betracht ziehen os.MkDirAll()

MkdirAll Erstellt ein Verzeichnis mit dem Namen path zusammen mit allen erforderlichen übergeordneten Elementen und gibt nil oder einen Fehler zurück.

Die Datei path_test.go ist eine gute Illustration zur Verwendung:

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

(Stellen Sie sicher, dass Sie einen sinnvollen Berechtigungswert angeben, wie in dieser Antwort erwähnt. )

VonC
quelle
3

Eine Dienstprogrammmethode wie die folgende kann verwendet werden, um dies zu lösen.

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.")
}
übersprungen
quelle
1

Dies ist eine Alternative, um dasselbe zu erreichen, aber es vermeidet Rennbedingungen, die durch zwei unterschiedliche "check ..and .. create" -Operationen verursacht werden.

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
quelle