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その両方が存在しない場合、自動的に作成することです。

どうやってやるの?

回答:


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

57
FileUtils#mkdir_pディレクトリ階層がすでに存在する場合でも動作します。このソリューションは、この缶ワンライナーに圧縮することができるので、(それだけで何もしない)プラスの文が必要になりますFileUtils.mkdir_p(File.dirname(some_path))
ユーリカ

1
@JosephK-私にとって、この(誤解を招く)EEXISTエラーは、最終的に権限の問題となりました。
TomG

81

ディレクトリが存在しない場合にディレクトリ作成する方法を探している人のために、ここに簡単な解決策があります:

require 'fileutils'

FileUtils.mkdir_p 'dir_name'

ユーレカのコメントに基づく。


1
これは@Eurekaのコメントです。「FileUtils#mkdir_pは、ディレクトリ階層がすでに存在する(何もしない)場合でも機能するので、このソリューションを圧縮して、1行でrequireステートメントを作成できます。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、2016年

4

他の回答に基づいて、何も起こりませんでした(動作しませんでした)。エラーはなく、ディレクトリは作成されませんでした。

これが私がする必要があることです:

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

FileUtils.mkdir_p('dir_name')送り返す応答をキャッチする変数を作成する必要がありました...それからすべてが魅力のように機能しました!


意味がありません。なぜあなたはリターンをキャッチする必要があるのですか?
Tim Kretschmer、2016年

@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.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がlibmagickwand-dev(Ubuntu)/ imagemagick(OSX)パッケージに依存して適切に動作するため、FileUtilsの依存関係のgem rmagickがRailsアプリをAmazon Web Servicesにデプロイできないため、このソリューションが必要でした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.