Sprawdź istnienie katalogu i utwórz, jeśli nie istnieje


388

Często piszę skrypty R, które generują wiele wyników. Uważam, że łatwiej jest umieścić te dane wyjściowe we własnych katalogach. To, co napisałem poniżej, sprawdzi istnienie katalogu i przejdzie do niego lub utworzy katalog, a następnie przejdzie do niego. Czy istnieje lepszy sposób na to?

mainDir <- "c:/path/to/main/dir"
subDir <- "outputDirectory"

if (file.exists(subDir)){
    setwd(file.path(mainDir, subDir))
} else {
    dir.create(file.path(mainDir, subDir))
    setwd(file.path(mainDir, subDir))

}

1
Jestem pewien, że widziałem funkcję R, która tworzy katalog tymczasowy z losowo generowaną nazwą i zwraca nazwę. Myślę, że jest podobny, który tworzy plik tymczasowy. Nie mogę ich znaleźć od razu, ale pakiet Databel ( cran.r-project.org/web/packages/DatABEL/index.html ) ma funkcję get_temporary_file_file_name.
PaulHurleyuk

42
Nigdy nie powinieneś używać setwd()w kodzie R - to w zasadzie przeczy idei używania katalogu roboczego, ponieważ nie możesz już łatwo przenosić kodu między komputerami.
hadley,

6
@hadley ciekawy temat do rozważenia, byłbym wdzięczny za twoje przemyślenia na temat innych metod w tym samym celu. W pracy wszystkie komputery są zsynchronizowane z tą samą siecią, więc ścieżki plików są spójne. Jeśli nie są, mamy większe problemy do rozwiązania niż przenośność skryptu. W tym konkretnym przykładzie napisałem skrypt, który zostanie załadowany na maszynę, która będzie przenoszona przez nasze parki narodowe przez 2 lata. Ten skrypt pobierze dane z lokalnej instancji SQL, wykona pewne przetwarzanie i wypluje plik .csv. Produkt końcowy będzie .batplikiem, którego użytkownik nigdy nie będzie musiał modyfikować.
Chase

@Chase Ale nie musisz setwdpracować ze ścieżkami sieciowymi. Wystarczy podać ścieżki, aby zapisać wyniki i nadal pracować z bieżącą ścieżką (tą, która jest ustalana przy rozpoczęciu sesji R.) Lub uruchom R z pożądanym katalogiem roboczym.
Marek

5
Tak. Lub sparametryzuj, out_dir <- "path/to/output/directory"a następnie użyj write.table(file = file.path(out_dir,"table_1.csv"), ...). Lub nawet out_file <- function(fnm) file.path("path/to/output/directory", fnm)wtedy write.table(file = out_file("table_1.csv"), ...)(podobna metoda, której używam podczas pracy z dyskami sieciowymi).
Marek

Odpowiedzi:


403

Użyj showWarnings = FALSE:

dir.create(file.path(mainDir, subDir), showWarnings = FALSE)
setwd(file.path(mainDir, subDir))

dir.create()nie ulega awarii, jeśli katalog już istnieje, po prostu wypisuje ostrzeżenie. Jeśli więc możesz żyć z widzeniem ostrzeżeń, nie ma problemu z robieniem tego:

dir.create(file.path(mainDir, subDir))
setwd(file.path(mainDir, subDir))

58
Pamiętaj, showWarnings = FALSEże korzystanie z tego spowoduje ukrycie również innych ostrzeżeń, takich jak niemożność utworzenia katalogu.
zelanix,

5
^ Czy istnieje sposób, aby ukryć tylko jedno konkretne ostrzeżenie?
Bas

2
Cześć, chcę utworzyć katalog zagnieżdżony, na przykład jeśli jestem w folderze test1, to w nim test2 wewnątrz to test3 ... ale teraz mam problem. Czy istnieje sposób, w jaki mogę utworzyć 3 poziom katalogu, nawet jeśli katalog1 nie zostanie zamknięty?
Praveen Kesani,

10
@PraveenKesani Czy tego szukasz: dir.create("test1/test2/test3/", recursive=TRUE)?
dziekan.

6
@Bas Naprawdę spóźniona odpowiedź, ale zignoruje suppressWarnings(<statement>)ostrzeżenia tylko dla tego stwierdzenia.
Ram RS

163

Od 16 kwietnia 2015 r. Wraz z wydaniem R 3.2.0pojawiła się nowa funkcja o nazwie dir.exists(). Aby użyć tej funkcji i utworzyć katalog, jeśli nie istnieje, możesz użyć:

ifelse(!dir.exists(file.path(mainDir, subDir)), dir.create(file.path(mainDir, subDir)), FALSE)

Będzie to powrót FALSEjeśli katalog już istnieje lub jest uncreatable, a TRUEjeżeli nie istniał, ale został pomyślnie utworzony.

Pamiętaj, że aby po prostu sprawdzić, czy katalog istnieje, możesz użyć

dir.exists(file.path(mainDir, subDir))

9
Należy zauważyć, że nie jest dobrą praktyką stosowanie ifelse()do rozgałęzień niewektoryzowanych.
Lionel Henry

2
@Bas, ponieważ twój kod odczytuje fałszywie, jakby dzieje się coś wektoryzowanego. To jak używanie wektoryzacji |zamiast skalara ||. Działa, ale jest złą praktyką.
Lionel Henry,

1
O cholera, więc robię moje, jeśli stwierdzenia również są błędne |, czy wektoryzacja jest powodem, dla którego ||czasami nie działa ? Wiem, że to nie jest temat, ale jestem zbyt chętny, aby się dowiedzieć. Zdecyduję się przejść i przeczytać więcej o wektoryzacji. Dzięki
Bas

4
Więc jaki jest najlepszy sposób na zrobienie tego, jeśli powinniśmy tego unikać ifelse?
KillerSnail

6
za pomocą if i else;)
Lionel Henry

17

Jeśli chodzi o ogólną architekturę, poleciłbym następującą strukturę w odniesieniu do tworzenia katalogów. Obejmuje to większość potencjalnych problemów, a wszelkie inne problemy z tworzeniem katalogu zostaną wykryte przez dir.createpołączenie.

mainDir <- "~"
subDir <- "outputDirectory"

if (file.exists(paste(mainDir, subDir, "/", sep = "/", collapse = "/"))) {
    cat("subDir exists in mainDir and is a directory")
} else if (file.exists(paste(mainDir, subDir, sep = "/", collapse = "/"))) {
    cat("subDir exists in mainDir but is a file")
    # you will probably want to handle this separately
} else {
    cat("subDir does not exist in mainDir - creating")
    dir.create(file.path(mainDir, subDir))
}

if (file.exists(paste(mainDir, subDir, "/", sep = "/", collapse = "/"))) {
    # By this point, the directory either existed or has been successfully created
    setwd(file.path(mainDir, subDir))
} else {
    cat("subDir does not exist")
    # Handle this error as appropriate
}

Należy również pamiętać, że jeśli ~/foonie istnieje, wywołanie dir.create('~/foo/bar')nie powiedzie się, chyba że zostanie to określone recursive = TRUE.


3
czy istnieje powód, dla którego używasz wklejania (...) zamiast file.path (mainDir, subDir). Również jeśli zrobiłeś ścieżkę <- file.path (mainDir, subDir), możesz użyć go 5 razy, aby instrukcje if były bardziej czytelne.
MikeF

14

Oto check prosty , i tworzy dir jeśli nie istnieje:

## Provide the dir name(i.e sub dir) that you want to create under main dir:
output_dir <- file.path(main_dir, sub_dir)

if (!dir.exists(output_dir)){
dir.create(output_dir)
} else {
    print("Dir already exists!")
}

9

Użycie file.exists () do testowania istnienia katalogu jest problemem w oryginalnym poście. Jeśli subDir zawiera nazwę istniejącego pliku (a nie tylko ścieżki), file.exists () zwróci TRUE, ale wywołanie setwd () zakończy się niepowodzeniem, ponieważ nie można ustawić katalogu roboczego tak, aby wskazywał na plik.

Poleciłbym użycie test_pliku (op = "- d", subDir), który zwróci „PRAWDA”, jeśli subDir jest istniejącym katalogiem, ale FALSE, jeśli subDir jest istniejącym plikiem lub nieistniejącym plikiem lub katalogiem. Podobnie, sprawdzanie pliku można wykonać op = "- f".

Ponadto, jak opisano w innym komentarzu, katalog roboczy jest częścią środowiska R i powinien być kontrolowany przez użytkownika, a nie skrypt. Skrypty nie powinny idealnie zmieniać środowiska R. Aby rozwiązać ten problem, mógłbym użyć options () do przechowywania globalnie dostępnego katalogu, w którym chciałbym mieć wszystkie moje dane wyjściowe.

Rozważmy zatem następujące rozwiązanie, w którym someUniqueTag jest tylko przedrostkiem zdefiniowanym przez programistę dla nazwy opcji, co sprawia, że ​​jest mało prawdopodobne, aby opcja o tej samej nazwie już istniała. (Na przykład, jeśli tworzysz pakiet o nazwie „filer”, możesz użyć filer.mainDir i filer.subDir).

Poniższy kod zostanie użyty do ustawienia opcji, które będą dostępne później w innych skryptach (unikając w ten sposób użycia setwd () w skrypcie), i do utworzenia folderu, jeśli to konieczne:

mainDir = "c:/path/to/main/dir"
subDir = "outputDirectory"

options(someUniqueTag.mainDir = mainDir)
options(someUniqueTag.subDir = "subDir")

if (!file_test("-d", file.path(mainDir, subDir)){
  if(file_test("-f", file.path(mainDir, subDir)) {
    stop("Path can't be created because a file with that name already exists.")
  } else {
    dir.create(file.path(mainDir, subDir))
  }
}

Następnie w każdym kolejnym skrypcie, który musiał manipulować plikiem w katalogu subDir, możesz użyć czegoś takiego:

mainDir = getOption(someUniqueTag.mainDir)
subDir = getOption(someUniqueTag.subDir)
filename = "fileToBeCreated.txt"
file.create(file.path(mainDir, subDir, filename))

To rozwiązanie pozostawia katalog roboczy pod kontrolą użytkownika.


8

Miałem problem z wersją 2.15.3, w wyniku której podczas próby rekurencyjnego tworzenia struktury drzewa na współużytkowanym dysku sieciowym dostałem błąd uprawnień.

Aby obejść tę dziwność, ręcznie tworzę strukturę;

mkdirs <- function(fp) {
    if(!file.exists(fp)) {
        mkdirs(dirname(fp))
        dir.create(fp)
    }
} 

mkdirs("H:/foo/bar")

5

Jednowarstwowy:

if (!dir.exists(output_dir)) {dir.create(output_dir)}

Przykład:

dateDIR <- as.character(Sys.Date())
outputDIR <- file.path(outD, dateDIR)
if (!dir.exists(outputDIR)) {dir.create(outputDIR)}

2

Aby dowiedzieć się, czy ścieżka jest prawidłowym katalogiem, spróbuj:

file.info(cacheDir)[1,"isdir"]

file.info nie dba o kreskę na końcu.

file.existsw systemie Windows nie powiedzie się katalog, jeśli zakończy się ukośnikiem i bez niego odniesie sukces. Nie można tego użyć do ustalenia, czy ścieżka jest katalogiem.

file.exists("R:/data/CCAM/CCAMC160b_echam5_A2-ct-uf.-5t05N.190to240E_level1000/cache/")
[1] FALSE

file.exists("R:/data/CCAM/CCAMC160b_echam5_A2-ct-uf.-5t05N.190to240E_level1000/cache")
[1] TRUE

file.info(cacheDir)["isdir"]

Co jest złego w tej odpowiedzi (poza pominięciem tej dir.create()części)? Czy stwierdzenia są błędne lub po prostu uważane za nieprzydatne w rozwiązaniu danego pytania?
mschilli
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.