สร้างไดเรกทอรีหากไม่มีอยู่ใน Ruby


156

ฉันพยายามสร้างไดเรกทอรีด้วยรหัสต่อไปนี้:

Dir.mkdir("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test")
    unless File.exists?("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test")  

อย่างไรก็ตามฉันได้รับข้อผิดพลาดนี้:

ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว - / Users / Luigi / Desktop / Survey_Final / Archived / Survey / test (Errno :: ENOENT)

เหตุใดไดเรกทอรีนี้จึงไม่ถูกสร้างโดยDir.mkdirคำสั่งด้านบน


4
File.exists?()ทำงานกับไฟล์และโฟลเดอร์ ไม่ทราบความแตกต่าง
Tin Man

คำตอบ:


263

คุณอาจพยายามสร้างไดเรกทอรีที่ซ้อนกัน สมมติว่าfooไม่มีอยู่คุณจะได้รับno such file or directoryข้อผิดพลาดสำหรับ:

Dir.mkdir 'foo/bar'
# => Errno::ENOENT: No such file or directory - 'foo/bar'

ในการสร้างไดเร็กทอรีที่ซ้อนกันในครั้งเดียวFileUtilsจำเป็นต้องมี:

require 'fileutils'
FileUtils.mkdir_p 'foo/bar'
# => ["foo/bar"]

แก้ไข 2: คุณไม่จำเป็นต้องใช้FileUtilsคุณอาจทำการโทรของระบบ (อัปเดตจาก @mu สั้นเกินไป):

> system 'mkdir', '-p', 'foo/bar' # worse version: system 'mkdir -p "foo/bar"'
=> true

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


5
system 'mkdir', '-p', 'foo/bar'จะเป็นรุ่นที่ดีกว่าของการsystemโทร ไม่มีความจำเป็นสำหรับกระบวนการเปลือกพิเศษหรือปกติเรื่องไร้สาระ quoting / หลบหนี / systemฉีดที่มาพร้อมกับรุ่นอาร์กิวเมนต์เดียวไม่เป็น
mu สั้นเกินไป

6
systemจะเปิดตัว/bin/shที่จะแยกสตริงแล้วเปลือกจะทำงานmkdir -p "foo/bar" /bin/mkdirดังนั้นคุณกำลังทำงานพิเศษ (สร้างสตริงคำสั่งเริ่มต้น/bin/shเพื่อดึงมันออกมาอีกครั้ง) และงานพิเศษบางอย่างนั้นทำให้คุณเปิดการโจมตีด้วยการฉีดเชลล์ (ใช้เวลาในคำแนะนำ CERT สำหรับ Ruby และคุณจะเห็นว่าเป็นเรื่องธรรมดา ปัญหานี้คือ)
mu สั้นเกินไป

1
@muistooshort @ zrl3dx การsystemโทรดีกว่าfileutilsอีกครั้งอย่างไร ฉันใช้ Windows และใช้mkdir_pงานได้ดีโดยไม่ต้องวาง subshell เพื่อแยกวิเคราะห์mkdir -pซึ่งจะล้มเหลวอยู่ดี ดีใจที่fileutilsเป็นทางเลือกแรกในคำตอบ
TWiStErRob

1
@TWiStErRob: อ่านความคิดเห็นของฉันอีกครั้งผมไม่ได้พูดอะไรเกี่ยวกับเรื่องfileutilsหรือmkdir_pสิ่งที่ผมกำลังบอกว่าจะดีกว่าsystem command, arg1, arg2, ... system command_with_arguments
mu สั้นเกินไป

3
@muistooshort อาขอโทษเพื่อให้คุณเพียงแค่บอกว่ามีวิธีที่ดีกว่าการทำตัวเลือกที่ดี :)
TWiStErRob

71

วิธีง่าย ๆ :

directory_name = "name"
Dir.mkdir(directory_name) unless File.exists?(directory_name)

8
หนึ่งจะใช้ File.directory มากกว่า File.exists?
Florin Asăvoaie

4
สมมติว่ามีไฟล์ปกติที่มีชื่อเดียวกัน คุณไม่สามารถสร้างไดเรกทอรีในกรณีเช่นนี้
Mikołaj Rozwadowski

3
นอกจากนี้ยังสร้างเงื่อนไขการแข่งขัน ไฟล์อาจถูกสร้างขึ้นหลังจากการตรวจสอบ แต่ก่อนที่จะสร้าง
Don Reba

25

อีกวิธีง่ายๆ:

Dir.mkdir('tmp/excel') unless Dir.exist?('tmp/excel')


หากคุณต้องการสร้างไดเรกทอรีที่ซ้อนกันสิ่งนี้จะไม่ทำงาน สำหรับเช่นฉันอยากจะสร้างต่อไปนี้ไดเรกทอรีแต่ใช้วิธีนี้ยก/home/jignesh/reports/test RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdirดังนั้นการแก้ปัญหาที่เชื่อถือได้คือการใช้FileUtils.mkdir_p
Jignesh Gohel

-5

แล้วไงDir.mkdir('dir') rescue nilล่ะ


3
หลีกเลี่ยงการใช้rescueในรูปแบบปรับปรุง
เซบาสเตียนปัลมา

1
สนใจที่จะอธิบายว่าทำไมฉันควรเขียนโค้ด 5 บรรทัดแทนที่จะเป็น 1? ฉันอยากเห็นคุณลอง
Vidar


1
ฉันทำไปแล้วและฉันไม่เห็นด้วยโดยสิ้นเชิงฉันคิดว่ามันโง่ดังนั้นคุณอาจจะสอนฉันได้ไหม
Vidar

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