如果在Ruby中使用File类不存在目录,如何创建目录?


121

我有这句话:

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

哪里

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

我想发生的是,如果路径中没有目录somedir或没有目录,或者没有目录some_subdir,我希望它自动创建它。

我怎样才能做到这一点?

Answers:


154

您可以使用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 2012年

1
我在回答中添加了仅核心解决方案:但是请注意,它实际上是重新实现的FileUtils.mkdir_p(这是专用于您的用例的方法)
Eureka 2012年

57
请注意,FileUtils#mkdir_p即使目录层次结构已经存在,它也可以工作(它什么也不做),因此可以将此解决方案压缩为可以加上一个require语句:FileUtils.mkdir_p(File.dirname(some_path))
Eureka 2012年

1
@JosephK-对我来说,这个(误导性)EEXIST错误最终是权限问题。
TomG

81

对于那些寻找一种创建目录(如果目录不存在)的方法,这是简单的解决方案:

require 'fileutils'

FileUtils.mkdir_p 'dir_name'

基于Eureka的评论


1
这是@Eureka的评论-“请注意,即使目录层次结构已经存在,FileUtils#mkdir_p仍然可以工作(它什么也没做),因此可以将该解决方案压缩为可以FileUtils.mkdir_p(File.dirname(some_path))
单线

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

2
使用此方法可能会遇到竞争状况,是否可以在File.exists之后创建目录?运行,但在执行Dir.mkdir之前。
马特·芬内隆

4

根据其他答案,没有任何反应(无效)。没有错误,也没有创建目录。

这是我需要做的:

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

我需要创建一个变量来捕获FileUtils.mkdir_p('dir_name')发送回的响应……然后一切都像个魅力!


没有道理。为什么需要获得回报?
蒂姆·克雷施默

@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将以相同的方式工作。
迈克尔

1

按照类似的方式(并取决于您的结构),这就是我们解决的屏幕快照存储位置:

在我们的环境设置(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

我需要此解决方案,因为FileUtils的依赖项rmagick阻止了我的Rails应用程序部署在Amazon Web Services上,因为rmagick依赖于libmagickwand-dev(Ubuntu)/ imagemagick(OSX)包才能正常工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.