ตรวจสอบการมีอยู่ของไดเรกทอรีและสร้างหากไม่มีอยู่


388

ฉันมักจะพบว่าตัวเองเขียนสคริปต์ R ที่สร้างผลลัพธ์จำนวนมาก ฉันคิดว่ามันสะอาดกว่าที่จะนำเอาท์พุทนี้ไปไว้ในไดเรกทอรีของตัวเอง สิ่งที่ฉันเขียนด้านล่างจะตรวจสอบการมีอยู่ของไดเรกทอรีและย้ายไปไว้ในไดเรกทอรีนั้นหรือสร้างไดเรกทอรีแล้วย้ายไปยังไดเรกทอรีนั้น มีวิธีที่ดีกว่าในการเข้าถึงสิ่งนี้หรือไม่?

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
ฉันแน่ใจว่าฉันเห็นฟังก์ชัน R ที่สร้างไดเรกทอรีชั่วคราวด้วยชื่อที่สร้างแบบสุ่มและส่งคืนชื่อ ฉันคิดว่ามีไฟล์ที่คล้ายกันที่สร้างไฟล์ชั่วคราว ฉันไม่พบพวกเขานอกเวลา แต่แพ็คเกจDatabel ( cran.r-project.org/web/packages/DatABEL/index.html ) มีฟังก์ชัน get_temporary_file_name
PaulHurleyuk

42
คุณไม่ควรใช้setwd()ในรหัส R - โดยพื้นฐานแล้วมันจะกำจัดความคิดในการใช้ไดเรกทอรีที่ใช้งานได้เพราะคุณไม่สามารถย้ายรหัสระหว่างคอมพิวเตอร์ได้อีกต่อไป
hadley

6
@Hadley หัวข้อที่น่าสนใจที่จะไตร่ตรองฉันขอขอบคุณความคิดของคุณเกี่ยวกับวิธีการอื่น ๆ ไปยังจุดสิ้นสุดเดียวกัน ที่ทำงานคอมพิวเตอร์ทุกเครื่องจะซิงค์กับเครือข่ายเดียวกันดังนั้นเส้นทางของไฟล์จึงสอดคล้องกัน หากไม่ใช่เรามีปัญหาที่ใหญ่กว่าที่จะจัดการได้ดีกว่าการพกพาของสคริปต์ ในตัวอย่างนี้ฉันเขียนสคริปต์ที่จะโหลดบนเครื่องที่จะพาไปรอบ ๆ อุทยานแห่งชาติของเราเป็นเวลา 2 ปี สคริปต์นี้จะดึงข้อมูลจากอินสแตนซ์ SQL ในเครื่องทำการประมวลผลและคาย acsv ออกมา ผลิตภัณฑ์สุดท้ายจะเป็น.batไฟล์ที่ผู้ใช้จะไม่ต้องแก้ไข
Chase

@Chase แต่คุณไม่จำเป็นต้องsetwdทำงานกับเส้นทางเครือข่าย คุณเพียงแค่ต้องระบุเส้นทางเพื่อบันทึกผลลัพธ์และยังคงทำงานกับเส้นทางปัจจุบัน (เส้นทางนั้นถูกสร้างขึ้นเมื่อเริ่มเซสชัน R) หรือเริ่ม R ด้วยไดเรกทอรีการทำงานที่ต้องการ
Marek

5
อ๋อ หรือ parametrize และการใช้งานแล้วout_dir <- "path/to/output/directory" write.table(file = file.path(out_dir,"table_1.csv"), ...)หรือแม้แต่out_file <- function(fnm) file.path("path/to/output/directory", fnm)แล้วwrite.table(file = out_file("table_1.csv"), ...)(วิธีที่คล้ายกันฉันใช้เมื่อทำงานกับไดรฟ์เครือข่าย)
Marek

คำตอบ:


403

การใช้showWarnings = FALSE:

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

dir.create()ไม่ผิดพลาดหากมีไดเรกทอรีอยู่แล้วมันก็แค่พิมพ์คำเตือน ดังนั้นหากคุณสามารถอยู่กับการดูคำเตือนได้ไม่มีปัญหาเพียงแค่ทำสิ่งนี้:

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

58
โปรดระวังเมื่อใช้showWarnings = FALSEสิ่งนี้จะเป็นการซ่อนคำเตือนอื่น ๆ เช่นไดเรกทอรีที่ไม่สามารถสร้างได้
zelanix

5
^ มีวิธีที่จะระงับคำเตือนที่เฉพาะเจาะจงเพียงคำเดียวหรือไม่?
Bas

2
สวัสดีฉันต้องการ ot สร้างไดเรกทอรีที่ซ้อนกันเช่นถ้าฉันอยู่ในโฟลเดอร์ test1 แล้วข้างในนั้น test2 ข้างในนั้น test3 ... แต่ตอนนี้ฉันกำลังประสบปัญหา มีวิธีที่ฉันสามารถสร้าง 3 ระดับของไดเรกทอรีแม้ว่า directory1 ไม่ออก?
Praveen Kesani

10
@PraveenKesani นี่คือสิ่งที่คุณกำลังมองหา: dir.create("test1/test2/test3/", recursive=TRUE)?
คณบดี

6
@Bas ตอบรับช้ามาก แต่suppressWarnings(<statement>)จะระงับการเตือนเพียงแค่คำสั่งนั้น
Ram RS

163

ในฐานะที่เป็นวันที่ 16 เมษายน 2015 ด้วยการเปิดตัวของมีฟังก์ชั่นใหม่ที่เรียกว่าR 3.2.0 dir.exists()หากต้องการใช้ฟังก์ชันนี้และสร้างไดเรกทอรีหากไม่มีอยู่คุณสามารถใช้:

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

สิ่งนี้จะส่งคืนFALSEหากไดเร็กทอรีนั้นมีอยู่แล้วหรือไม่สามารถรักษาได้และTRUEถ้ามันไม่มีอยู่ แต่ถูกสร้างขึ้นสำเร็จ

โปรดทราบว่าเพียงตรวจสอบว่ามีไดเรกทอรีอยู่หรือไม่คุณสามารถใช้

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

9
เพียงสังเกตว่าไม่ใช่วิธีปฏิบัติที่ดีที่จะใช้ifelse()สำหรับการแยกสาขาที่ไม่ใช่เวกเตอร์
ไลโอเนลเฮนรี

2
@Bas เนื่องจากรหัสของคุณอ่านอย่างผิด ๆ ราวกับมีบางสิ่งที่ vectorised กำลังเกิดขึ้น มันก็เหมือนกับการใช้ vectorised แทนเกลา| ||มันใช้งานได้ แต่เป็นการฝึกฝนที่ไม่ดี
ไลโอเนลเฮนรี

1
โอ้ด่าฉันก็เลยทำถ้าคำสั่งผิดด้วยการใช้|vectorization เป็นเหตุผลที่||บางครั้งมันใช้ไม่ได้หรือเปล่า? ฉันรู้ว่านี่เป็นหัวข้อนอก แต่ฉันก็อยากรู้ ฉันจะ defo ไปและอ่านเพิ่มเติมเกี่ยวกับ vectorization ขอบคุณ
Bas

4
ดังนั้นสิ่งที่เป็นวิธีปฏิบัติที่ดีที่สุดของการทำเช่นนี้หากเราควรหลีกเลี่ยงifelse?
KillerSnail

6
ใช้ if and else;)
Lionel Henry

17

ในแง่ของสถาปัตยกรรมทั่วไปฉันอยากจะแนะนำโครงสร้างต่อไปนี้เกี่ยวกับการสร้างไดเรกทอรี ซึ่งจะครอบคลุมถึงปัญหาที่อาจเกิดขึ้นส่วนใหญ่และปัญหาอื่น ๆ ที่มีการสร้างไดเรกทอรีจะถูกตรวจพบโดยการdir.createโทร

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
}

นอกจากนี้ยังทราบว่าหาก~/fooไม่ได้อยู่แล้วเรียกร้องให้จะล้มเหลวเว้นแต่คุณจะระบุdir.create('~/foo/bar')recursive = TRUE


3
มีเหตุผลที่คุณใช้ paste (... ) vs file.path (mainDir, subDir) นอกจากนี้หากคุณทำพา ธ <- file.path (mainDir, subDir) คุณสามารถใช้ซ้ำได้ 5 ครั้งทำให้คำสั่ง if อ่านได้ง่ายขึ้น
MikeF

14

นี่คือการตรวจสอบที่เรียบง่าย , และสร้าง dir ถ้าไม่ได้อยู่แล้ว:

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

การใช้ file.exists () เพื่อทดสอบการมีอยู่ของไดเรกทอรีเป็นปัญหาในการโพสต์ต้นฉบับ หาก subDir รวมชื่อของไฟล์ที่มีอยู่แล้ว (แทนที่จะเป็นเพียงพา ธ ) file.exists () จะส่งกลับค่า TRUE แต่การเรียกไปยัง setwd () จะล้มเหลวเนื่องจากคุณไม่สามารถตั้งค่าไดเรกทอรีทำงานให้ชี้ไปที่ไฟล์ได้

ฉันขอแนะนำให้ใช้ file_test (op = "- d", subDir) ซึ่งจะส่งกลับ "TRUE" หาก subDir เป็นไดเรกทอรีที่มีอยู่ แต่เป็น FALSE หาก subDir เป็นไฟล์ที่มีอยู่หรือไฟล์หรือไดเรกทอรีที่ไม่มีอยู่จริง การตรวจสอบไฟล์สามารถทำได้ด้วย op = "- f"

นอกจากนี้ดังที่อธิบายไว้ในความคิดเห็นอื่นไดเร็กทอรีการทำงานเป็นส่วนหนึ่งของสภาพแวดล้อม R และควรได้รับการควบคุมโดยผู้ใช้ไม่ใช่สคริปต์ สคริปต์ควรไม่เปลี่ยนสภาพแวดล้อม R เพื่อแก้ไขปัญหานี้ฉันอาจใช้ตัวเลือก () เพื่อจัดเก็บไดเรกทอรีที่มีอยู่ทั่วโลกซึ่งฉันต้องการเอาท์พุททั้งหมดของฉัน

ดังนั้นให้พิจารณาวิธีการแก้ปัญหาต่อไปนี้โดย someUniqueTag เป็นเพียงส่วนนำหน้าที่กำหนดโดยโปรแกรมเมอร์สำหรับชื่อตัวเลือกซึ่งทำให้ไม่น่าจะมีตัวเลือกที่มีชื่อเดียวกันนี้อยู่แล้ว (ตัวอย่างเช่นหากคุณกำลังพัฒนาแพ็คเกจชื่อ "filer" คุณอาจใช้ filer.mainDir และ filer.subDir)

รหัสต่อไปนี้จะถูกใช้เพื่อตั้งค่าตัวเลือกที่พร้อมใช้งานในภายหลังในสคริปต์อื่น ๆ (ดังนั้นหลีกเลี่ยงการใช้ setwd () ในสคริปต์) และสร้างโฟลเดอร์หากจำเป็น:

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

จากนั้นในสคริปต์ที่ตามมาใด ๆ ที่ต้องการจัดการไฟล์ใน subDir คุณอาจใช้สิ่งต่อไปนี้:

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

วิธีการแก้ปัญหานี้ทำให้ไดเรกทอรีทำงานภายใต้การควบคุมของผู้ใช้


8

ฉันมีปัญหากับ R 2.15.3 ในขณะที่พยายามสร้างโครงสร้างแบบทรีบนไดรฟ์เครือข่ายที่แชร์ซ้ำฉันจะได้รับข้อผิดพลาดในการขออนุญาต

เพื่อให้ได้สิ่งที่แปลกประหลาดนี้ฉันสร้างโครงสร้างด้วยตนเอง

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

mkdirs("H:/foo/bar")

5

หนึ่งในสายการบิน:

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

ตัวอย่าง:

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

2

หากต้องการดูว่าเส้นทางเป็นไดเรกทอรีที่ถูกต้องหรือไม่ลอง:

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

file.info ไม่สนใจเกี่ยวกับการเฉือนในตอนท้าย

file.existsบน Windows จะล้มเหลวสำหรับไดเรกทอรีถ้ามันจบลงด้วยเครื่องหมายทับและประสบความสำเร็จโดยไม่มีมัน ดังนั้นจึงไม่สามารถใช้เพื่อกำหนดว่าเส้นทางเป็นไดเรกทอรีหรือไม่

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"]

มีอะไรผิดปกติเกี่ยวกับคำตอบนี้ (ด้านข้างไม่รวมdir.create()ส่วน) ข้อความไม่ถูกต้องหรือเพิ่งพิจารณาว่าไม่มีประโยชน์ในการแก้ปัญหาที่เกิดขึ้น?
mschilli
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.