Як створити вкладені каталоги за допомогою Mkdir в Golang?


96

Я намагаюся створити набір вкладених каталогів із виконуваного файлу Go, наприклад 'dir1 / dir2 / dir3'. Мені вдалося створити єдиний каталог за допомогою цього рядка:

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

Однак я не уявляю, як підходити до створення заздалегідь визначеного вкладеного набору каталогів всередині цього каталогу.

Відповіді:


181

os.Mkdirвикористовується для створення єдиного каталогу. Щоб створити шлях до папки, спробуйте скористатися:

os.MkdirAll(folderPath, os.ModePerm)

Перейти до документації

func Помилка MkdirAll (рядок шляху, Perm FileMode)

MkdirAll створює каталог з іменем path, разом з усіма необхідними батьками, і повертає nil, або ж повертає помилку. Біти дозволу perm використовуються для всіх каталогів, які створює MkdirAll. Якщо шлях - це вже каталог, MkdirAll нічого не робить і повертає нуль.

Редагувати:

os.ModePermНатомість оновлено для правильного використання .
Для конкатенації шляхів до файлів використовуйте пакет, path/filepathяк описано у відповіді @Chris.


@CodeWarrior: Дякую за пінг. Я оновив свою відповідь і проголосував за Кріса
Аніса

Дякую @chris! :)
Thales P

1
Можливо, ви захочете вибрати між 0755і os.ModePerm.
updogliu

102

Таким чином, вам не потрібно використовувати будь-які магічні цифри:

os.MkdirAll(newPath, os.ModePerm)

Крім того, замість використання + для створення шляхів, ви можете використовувати:

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

Вище використовуються правильні роздільники автоматично для кожної платформи для вас.


2
Це правильна відповідь. Набагато простіший та агностичний на платформі.
Ден Еспарза,

6

Якщо проблема полягає у створенні всіх необхідних батьківських каталогів, ви можете розглянути можливість використання os.MkDirAll()

MkdirAll створює каталог з іменем path, разом із усіма необхідними батьками, і повертає nil, або повертає помилку.

Path_test.go є хорошою ілюстрацією того, як використовувати його:

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

(Обов’язково вкажіть розумне значення дозволу, як зазначено у цій відповіді )


3

Для вирішення цього можна використовувати такий утилітний метод, як наведений нижче.

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

Це одна з альтернатив для досягнення того самого, але вона дозволяє уникнути перегонових умов, спричинених двома різними операціями "перевірка .. та .. створення".

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
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.