Как создать вложенные каталоги с помощью Mkdir в Golang?
Я пытаюсь создать набор вложенных каталогов из исполняемого файла Go, такого как 'dir1/dir2/dir3'. Мне удалось создать один каталог с этой строкой:
os.Mkdir("." + string(filepath.Separator) + c.Args().First(),0777);
Однако я понятия не имею, как подойти к созданию заранее определенного вложенного набора каталогов внутри этого каталога.
Ответы
Ответ 1
os.Mkdir
используется для создания одного каталога. Чтобы создать путь к папке, попробуйте использовать:
os.MkdirAll(folderPath, os.ModePerm)
Перейти документация
func MkdirAll (строка пути, пермский FileMode) ошибка
MkdirAll создает каталог с именем path вместе со всеми необходимыми родителями и возвращает nil, либо возвращает ошибку. Биты разрешений perm используются для всех каталогов, которые создает MkdirAll. Если путь уже является каталогом, MkdirAll ничего не делает и возвращает nil.
Редактировать:
Обновлен для правильного использования os.ModePerm
.
Для объединения путей к файлам используйте path/filepath
к файлу, как описано в ответе @Chris.
Ответ 2
Таким образом, вам не нужно использовать магические числа:
os.MkdirAll(newPath, os.ModePerm)
Кроме того, вместо использования + для создания путей вы можете использовать:
import "path/filepath"
path := filepath.Join(someRootPath, someSubPath)
Вышеупомянутые правила используют для каждой платформы правильные разделители на каждой платформе.
Ответ 3
Если проблема заключается в создании всех необходимых родительских каталогов, вы можете рассмотреть возможность использования 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_")
...
}
(Не забудьте указать разумное значение разрешения, как указано в этом ответе)
Ответ 4
Для решения этой проблемы можно использовать такой метод, как приведенный ниже.
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.")
}
Ответ 5
Это одна альтернатива для достижения того же самого, но она позволяет избежать состояния гонки, вызванного наличием двух разных операций "проверить.. и.. создать".
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
}
}