ฉันจะสร้างไดเร็กทอรีได้อย่างไรหากไม่มีอยู่โดยใช้คลาสไฟล์ใน Ruby


123

ฉันมีคำสั่งนี้:

File.open(some_path, 'w+') { |f| f.write(builder.to_html)  }

ที่ไหน

some_path = "somedir/some_subdir/some-file.html"

สิ่งที่ฉันต้องการให้เกิดขึ้นคือถ้าไม่มีไดเร็กทอรีที่เรียกsomedirหรือsome_subdirหรือทั้งสองอย่างในเส้นทางฉันต้องการให้สร้างโดยอัตโนมัติ

ฉันจะทำเช่นนั้นได้อย่างไร?

คำตอบ:


155

คุณสามารถใช้ FileUtils เพื่อสร้างไดเร็กทอรีพาเรนต์ซ้ำได้หากยังไม่มีอยู่:

require 'fileutils'

dirname = File.dirname(some_path)
unless File.directory?(dirname)
  FileUtils.mkdir_p(dirname)
end

แก้ไข: นี่คือวิธีแก้ปัญหาโดยใช้ไลบรารีหลักเท่านั้น (ไม่แนะนำให้ใช้วงล้อซ้ำ)

dirname = File.dirname(some_path)
tokens = dirname.split(/[\/\\]/) # don't forget the backslash for Windows! And to escape both "\" and "/"

1.upto(tokens.size) do |n|
  dir = tokens[0...n]
  Dir.mkdir(dir) unless Dir.exist?(dir)
end


โอวตกลง. ฉันหมายถึงแกนกลางไม่ใช่ stdlib ไม่ว่าจะด้วยวิธีใดก็ไม่เป็นไร นี้ได้ผล ขอบคุณ!
marcamillion

1
ฉันได้เพิ่มโซลูชันหลักเท่านั้นในคำตอบของฉัน: อย่างไรก็ตามโปรดทราบว่าการเติมเต็มโดยพื้นฐานแล้วFileUtils.mkdir_p(ซึ่งเป็นวิธีการเฉพาะสำหรับกรณีการใช้งานของคุณ)
Eureka

57
โปรดทราบว่าใช้FileUtils#mkdir_pงานได้แม้ว่าจะมีลำดับชั้นของไดเร็กทอรีอยู่แล้ว (แต่ก็ไม่ได้ทำอะไรเลย) ดังนั้นจึงสามารถบีบอัดโซลูชันนี้ลงในซับเดียวได้พร้อมกับคำสั่งที่ต้องการ:FileUtils.mkdir_p(File.dirname(some_path))
Eureka

1
@JosephK - สำหรับฉันข้อผิดพลาด EEXIST นี้ (ทำให้เข้าใจผิด) กลายเป็นปัญหาการอนุญาต
TomG

82

สำหรับผู้ที่มองหาวิธีสร้างไดเร็กทอรีหากไม่มีอยู่นี่คือวิธีง่ายๆ:

require 'fileutils'

FileUtils.mkdir_p 'dir_name'

ขึ้นอยู่กับยูเรก้าของความคิดเห็น


1
นี่คือความคิดเห็นของ @ Eureka - "โปรดทราบว่า FileUtils # mkdir_p ใช้งานได้แม้ว่าจะมีลำดับชั้นของไดเร็กทอรีอยู่แล้วก็ตาม (แต่ก็ไม่ได้ทำอะไรเลย) ดังนั้นจึงสามารถบีบอัดโซลูชันนี้ลงในบรรทัดเดียวได้พร้อมด้วยคำสั่งที่ต้องการ: FileUtils.mkdir_p(File.dirname(some_path))"
Darpan

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

2
คุณอาจพบเงื่อนไขการแข่งขันโดยใช้วิธีนี้ไดเร็กทอรีสามารถสร้างขึ้นหลังจาก File.exists? ทำงาน แต่ก่อนที่ Dir.mkdir จะดำเนินการ
Matt Fenelon

4

จากคำตอบของคนอื่นไม่มีอะไรเกิดขึ้น (ไม่ได้ผล) ไม่มีข้อผิดพลาดและไม่มีการสร้างไดเร็กทอรี

นี่คือสิ่งที่ฉันต้องทำ:

require 'fileutils'
response = FileUtils.mkdir_p('dir_name')

ฉันต้องสร้างตัวแปรเพื่อจับการตอบสนองที่FileUtils.mkdir_p('dir_name')ส่งกลับมา ... จากนั้นทุกอย่างก็เป็นไปอย่างมีเสน่ห์!


ไม่สมเหตุสมผล ทำไมคุณต้องจับคืน?
Tim Kretschmer

@huanson ผมไม่ได้ต้องการที่จะจับกลับมา ... response = FileUtils.mkdir_p('dir_name')แต่ตรรกะไม่ได้ทำงานจนกว่าฉันจะสร้าง ถ้าฉันไม่ได้สร้างตัวแปรนี้FileUtils.mkdir_p('dir_name')ก็ไม่ได้ผลสำหรับฉัน ... หรืออย่างน้อยนั่นคือสิ่งที่ฉันจำได้ว่าเกิดขึ้น (คำตอบนี้มีอายุมากกว่า 1 ปี) ฉันจะไม่แปลกใจถ้า Ruby เวอร์ชันใหม่กว่าสามารถแก้ไขปัญหานี้ได้
skplunkerin

2

ใช้แล้วเป็นPathnameไง?

require 'pathname'
some_path = Pathname("somedir/some_subdir/some-file.html")
some_path.dirname.mkdir_p
some_path.write(builder.to_html)

1
ใช้งานได้some_path.dirname.mkpathแทนsome_path.dirname.mkdir_p
Mauro Nidola

1
+1 mkpathบน นอกจากนี้หากคุณมีไดเร็กทอรีไม่ใช่เส้นทางก็ไม่จำเป็นต้องdirnameมีเช่น Pathname ("somedir / some_subdir") mkpath จะทำงานในลักษณะเดียวกัน
Michael

1

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

ในการตั้งค่า env ของเรา (env.rb)

screenshotfolder = "./screenshots/#{Time.new.strftime("%Y%m%d%H%M%S")}"
unless File.directory?(screenshotfolder)
  FileUtils.mkdir_p(screenshotfolder)
end
Before do
  @screenshotfolder = screenshotfolder
  ...
end

และใน hooks.rb ของเรา

  screenshotName = "#{@screenshotfolder}/failed-#{scenario_object.title.gsub(/\s+/,"_")}-#{Time.new.strftime("%Y%m%d%H%M%S")}_screenshot.png";
  @browser.take_screenshot(screenshotName) if scenario.failed?

  embed(screenshotName, "image/png", "SCREENSHOT") if scenario.failed?

1

โซลูชันเดียว "ไลบรารีหลัก" ของคำตอบยอดนิยมไม่สมบูรณ์ หากคุณต้องการใช้เฉพาะไลบรารีหลักให้ใช้สิ่งต่อไปนี้:

target_dir = ""

Dir.glob("/#{File.join("**", "path/to/parent_of_some_dir")}") do |folder|
  target_dir = "#{File.expand_path(folder)}/somedir/some_subdir/"
end

# Splits name into pieces
tokens = target_dir.split(/\//)

# Start at '/'
new_dir = '/'

# Iterate over array of directory names
1.upto(tokens.size - 1) do |n|

  # Builds directory path one folder at a time from top to bottom
  unless n == (tokens.size - 1)
    new_dir << "#{tokens[n].to_s}/" # All folders except innermost folder
  else
    new_dir << "#{tokens[n].to_s}" # Innermost folder
  end

  # Creates directory as long as it doesn't already exist
  Dir.mkdir(new_dir) unless Dir.exist?(new_dir)
end

ฉันต้องการโซลูชันนี้เนื่องจาก rmagick อัญมณีการพึ่งพาของ FileUtils ป้องกันไม่ให้แอป Rails ของฉันใช้งานบน Amazon Web Services เนื่องจาก rmagick ขึ้นอยู่กับแพ็คเกจ libmagickwand-dev (Ubuntu) / imagemagick (OSX) เพื่อให้ทำงานได้อย่างถูกต้อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.