Überprüfen Sie das Vorhandensein eines Verzeichnisses und erstellen Sie es, wenn es nicht vorhanden ist

388

Ich schreibe oft R-Skripte, die viel Ausgabe erzeugen. Ich finde es sauberer, diese Ausgabe in ein eigenes Verzeichnis zu stellen. Was ich unten geschrieben habe, prüft, ob ein Verzeichnis vorhanden ist, und verschiebt es, oder erstellt das Verzeichnis und verschiebt es dann. Gibt es einen besseren Weg, dies zu erreichen?

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))

}
Verfolgungsjagd
quelle
1
Ich bin sicher, ich habe eine R-Funktion gesehen, die ein temporäres Verzeichnis mit einem zufällig generierten Namen erstellt und den Namen zurückgibt. Ich denke, es gibt eine ähnliche, die eine temporäre Datei erstellt. Ich kann sie nicht ohne weiteres finden, aber das Databel-Paket ( cran.r-project.org/web/packages/DatABEL/index.html ) hat eine Funktion get_temporary_file_name.
Paul Hurleyuk
42
Sie sollten niemals setwd()R-Code verwenden - dies widerspricht im Grunde der Idee, ein Arbeitsverzeichnis zu verwenden, da Sie Ihren Code nicht mehr einfach zwischen Computern verschieben können.
Hadley
6
@ Hadley interessantes Thema zum Nachdenken, ich würde mich über Ihre Gedanken zu anderen Methoden zum gleichen Zweck freuen. Bei der Arbeit werden alle Computer mit demselben Netzwerk synchronisiert, sodass die Dateipfade konsistent sind. Wenn dies nicht der Fall ist, müssen wir uns mit größeren Problemen befassen als mit der Portabilität eines Skripts. In diesem Beispiel habe ich ein Skript geschrieben, das auf eine Maschine geladen wird, die zwei Jahre lang in unseren Nationalparks herumgeführt wird. Dieses Skript greift auf Daten von einer lokalen SQL-Instanz zu, verarbeitet sie und spuckt eine CSV-Datei aus. Das Endprodukt ist eine .batDatei, die der Endbenutzer niemals ändern muss.
Chase
@Chase Sie müssen jedoch nicht setwdmit Netzwerkpfaden arbeiten. Sie müssen nur Pfade angeben, um Ergebnisse zu speichern und trotzdem mit dem aktuellen Pfad zu arbeiten (dem Pfad, der beim Start der R-Sitzung festgelegt wurde). Oder starten Sie R mit dem gewünschten Arbeitsverzeichnis.
Marek
5
Ja. Oder parametrisieren out_dir <- "path/to/output/directory"und dann verwenden write.table(file = file.path(out_dir,"table_1.csv"), ...). Oder sogar out_file <- function(fnm) file.path("path/to/output/directory", fnm)und dann write.table(file = out_file("table_1.csv"), ...)(ähnliche Methode verwende ich bei der Arbeit mit Netzwerklaufwerken).
Marek

Antworten:

403

Verwendung showWarnings = FALSE:

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

dir.create()stürzt nicht ab, wenn das Verzeichnis bereits vorhanden ist, sondern druckt nur eine Warnung aus. Wenn Sie also mit Warnungen leben können, ist es kein Problem, dies einfach zu tun:

dir.create(file.path(mainDir, subDir))
setwd(file.path(mainDir, subDir))
robbrit
quelle
58
Beachten Sie bei der Verwendung, showWarnings = FALSEdass dadurch auch andere Warnungen ausgeblendet werden, z. B., dass das Verzeichnis nicht erstellt werden kann.
Zelanix
5
^ Gibt es eine Möglichkeit, nur eine bestimmte Warnung zu unterdrücken?
Bas
2
Hallo, ich möchte kein verschachteltes Verzeichnis erstellen, wenn ich mich im Ordner test1 befinde, dann darin test2 darin test3 ... aber im Moment stehe ich vor einem Problem. Gibt es eine Möglichkeit, 3 Verzeichnisebenen zu erstellen, auch wenn Verzeichnis1 nicht beendet wird?
Praveen Kesani
10
@PraveenKesani Ist es das, wonach Sie suchen : dir.create("test1/test2/test3/", recursive=TRUE)?
Dekan.
6
@Bas Wirklich späte Antwort, suppressWarnings(<statement>)unterdrückt aber Warnungen nur für diese Aussage.
Ram RS
163

Ab dem 16. April 2015 gibt es mit der Veröffentlichung R 3.2.0eine neue Funktion namens dir.exists(). Um diese Funktion zu verwenden und das Verzeichnis zu erstellen, falls es nicht vorhanden ist, können Sie Folgendes verwenden:

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

Dies wird zurückgegeben, FALSEwenn das Verzeichnis bereits vorhanden ist oder nicht erstellt werden kann und TRUEwenn es nicht vorhanden war, aber erfolgreich erstellt wurde.

Beachten Sie, dass Sie einfach überprüfen können, ob das Verzeichnis vorhanden ist

dir.exists(file.path(mainDir, subDir))
Molx
quelle
9
Nur um zu beachten, es ist keine gute Praxis, ifelse()für nicht vektorisierte Verzweigungen zu verwenden.
Lionel Henry
2
@Bas, weil Ihr Code fälschlicherweise so liest, als ob etwas Vektorisiertes passiert. Es ist wie mit Vektor |anstelle von Skalar ||. Es funktioniert, ist aber eine schlechte Praxis.
Lionel Henry
1
Oh verdammt, also habe ich meine if-Anweisungen auch falsch gemacht |, ist die Vektorisierung der Grund, warum sie ||manchmal nicht funktioniert ? Ich weiß, dass dies kein Thema ist, aber ich bin einfach zu eifrig, es herauszufinden. Ich werde auf jeden Fall mehr über Vektorisierung lesen. Danke
Bas
4
Was ist die beste Vorgehensweise, wenn wir dies vermeiden sollten ifelse?
KillerSnail
6
mit if und else;)
Lionel Henry
17

In Bezug auf die allgemeine Architektur würde ich die folgende Struktur in Bezug auf die Verzeichniserstellung empfehlen. Dies deckt die meisten potenziellen Probleme ab, und alle anderen Probleme bei der Verzeichniserstellung werden vom dir.createAufruf erkannt .

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
}

Beachten Sie auch, dass ~/fooein Aufruf von dir.create('~/foo/bar')fehlschlägt , wenn er nicht vorhanden ist , wenn er nicht vorhanden ist recursive = TRUE.

Zelanix
quelle
3
Gibt es einen Grund, warum Sie paste (...) vs file.path (mainDir, subDir) verwenden? Auch wenn Sie einen Pfad <- file.path (mainDir, subDir) erstellt haben, können Sie ihn fünfmal wiederverwenden, um die if-Anweisungen besser lesbar zu machen.
MikeF
14

Hier ist die einfache Prüfung , und erstellt das Verzeichnis , wenn nicht vorhanden ist :

## 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!")
}
Surya
quelle
9

Die Verwendung von file.exists () zum Testen der Existenz des Verzeichnisses ist ein Problem im ursprünglichen Beitrag. Wenn subDir den Namen einer vorhandenen Datei enthält (und nicht nur einen Pfad), gibt file.exists () TRUE zurück, aber der Aufruf von setwd () schlägt fehl, da Sie das Arbeitsverzeichnis nicht so einstellen können, dass es auf eine Datei verweist.

Ich würde die Verwendung von file_test (op = "- d", subDir) empfehlen, das "TRUE" zurückgibt, wenn subDir ein vorhandenes Verzeichnis ist, aber FALSE, wenn subDir eine vorhandene Datei oder eine nicht vorhandene Datei oder ein nicht vorhandenes Verzeichnis ist. Ebenso kann die Suche nach einer Datei mit op = "- f" durchgeführt werden.

Wie in einem anderen Kommentar beschrieben, ist das Arbeitsverzeichnis außerdem Teil der R-Umgebung und sollte vom Benutzer gesteuert werden, nicht von einem Skript. Skripte sollten im Idealfall die R-Umgebung nicht ändern. Um dieses Problem zu beheben, verwende ich möglicherweise options (), um ein global verfügbares Verzeichnis zu speichern, in dem ich meine gesamte Ausgabe haben möchte.

Betrachten Sie daher die folgende Lösung, bei der someUniqueTag nur ein vom Programmierer definiertes Präfix für den Optionsnamen ist, sodass es unwahrscheinlich ist, dass bereits eine Option mit demselben Namen vorhanden ist. (Wenn Sie beispielsweise ein Paket mit dem Namen "filer" entwickelt haben, können Sie filer.mainDir und filer.subDir verwenden.)

Der folgende Code wird verwendet, um Optionen festzulegen, die später in anderen Skripten verwendet werden können (wodurch die Verwendung von setwd () in einem Skript vermieden wird), und um den Ordner bei Bedarf zu erstellen:

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))
  }
}

In jedem nachfolgenden Skript, das eine Datei in subDir bearbeiten muss, können Sie dann Folgendes verwenden:

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

Diese Lösung verlässt das Arbeitsverzeichnis unter der Kontrolle des Benutzers.

G Poole
quelle
8

Ich hatte ein Problem mit R 2.15.3, bei dem beim Versuch, eine Baumstruktur rekursiv auf einem freigegebenen Netzlaufwerk zu erstellen, ein Berechtigungsfehler angezeigt wurde.

Um diese Kuriosität zu umgehen, erstelle ich die Struktur manuell.

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

mkdirs("H:/foo/bar")
user425678
quelle
5

Einzeiler:

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

Beispiel:

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

Um herauszufinden, ob ein Pfad ein gültiges Verzeichnis ist, versuchen Sie:

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

file.info kümmert sich nicht um einen Schrägstrich am Ende.

file.existsUnter Windows schlägt ein Verzeichnis fehl, wenn es mit einem Schrägstrich endet und ohne dieses erfolgreich ist. Dies kann also nicht verwendet werden, um festzustellen, ob ein Pfad ein Verzeichnis ist.

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"]
user3807179
quelle
Was ist falsch an dieser Antwort (abgesehen davon, dass das dir.create()Teil nicht enthalten ist)? Sind die Aussagen falsch oder werden sie nur als nicht hilfreich angesehen, um die vorliegende Frage zu lösen?
Mschilli