Rubyでフォルダーからすべてのファイルの名前を取得する


回答:


537

次のショートカットオプションもあります

Dir["/path/to/search/*"]

また、任意のフォルダーまたはサブフォルダー内のすべてのRubyファイルを検索する場合:

Dir["/path/to/search/**/*.rb"]

5
または、Dir :: glob()で同じことを行うことができます
Yoann Le Touche

2
また、次の./...代わりに使用~/
Minh Triet 2014

5
なぜこれが望ましいのですか?
BvuRVKyUVlViVIc7 2015

1
@MinhTrietそれは何をしますか?それは何が望ましいですか?
スティーブンマードック、2015

9
@marflar- ./現在のディレクトリを意味します/が、これはルートマウントポイントであり~/、ユーザーのホームディレクトリです。プロジェクト全体を別の場所に移動した場合、最初のプロジェクトは機能しますが、他の2つはおそらく機能しません。
mirichan

170
Dir.entries(folder)

例:

Dir.entries(".")

出典:http : //ruby-doc.org/core/classes/Dir.html#method-c-entries


15
彼はSOを使用して、彼がたった今質問に対する答えを文書化しているようです。一種のメモだと思います。これで多くの間違いをDir#glob見つけることはできません-結局のところ、これは少し不完全です(たとえば、おそらく言及されているかもしれません)が、他の誰かが本当に良い回答を投稿するのを妨げるものは何もありません。'もちろん、私はほとんど「グラスハーフフル」のような男です...
マイクウッドハウス

1
@マイク:物事の壮大な計画では、それはおそらく大したことではありません。そして、あなたが質問と回答が良かったと言うように、それはサイトにとって全体的にプラスになるかもしれません。しかし、ここでは質問と回答の両方が非常に少ないため、特に有用とは思われません。
テレマコス

17
@TelemachusはDirめったに使用せず、必要になるたびにドキュメントを読む必要があります。質問と回答をここに投稿しましたので、後で見つけたり、同じ質問で誰かを助けたりすることができます。私はSOポッドキャストでそのような振る舞いに何も問題はないと聞いたと思います。より良い答えがある場合は、投稿してください。私は知っていることを投稿しました。私はRuby忍者ではありません。投票数が最も多い回答を定期的に受け入れます。
ジェリコ・フィリピン

これは、より良い選択肢であることが可能Dir[]か、Dir.glob引数が変数であるとき。の場合path = '/tmp'、比較: Dir.glob("#{path}/*")Dir.entries(path)。戻り値は少し異なりますが( "。"、 "..")、後者は一目で理解するのが簡単です。
ベンジャミンオークス2013年

92

次のスニペットは、ディレクトリ内のファイルの名前を正確に示しており"."、サブディレクトリと".."ドット付きフォルダをスキップしています。

Dir.entries("your/folder").select {|f| !File.directory? f}

19
...select {|f| File.file? f}より明確な意味とより短い構文のためにも行うことができます。
Automatico

2
@squixyあなたはそれを正しく書きましたか?:Dir.entries("your/folder").select {|f| File.file? f}
Automatico

9
うん。!File.directory?機能してFile.file?いますが機能していません。
Kamil Lelonek 2014

2
@squixy同じ問題がありました。私の場合、Dir.foreachによって返されたファイル名だけでなく、フルパスを指定する必要があります
TheLukeMcCarthy

6
.reject {|f| File.directory? f}よりもきれいなようです.select{|f| !File.directory? f}。ああ、今、最初のコメントが表示されます...いいですね。
Ian

36

すべてのファイル(厳密にはファイルのみ)を再帰的に取得するには:

Dir.glob('path/**/*').select{ |e| File.file? e }

またはディレクトリではないもの(File.file?通常でないファイルは拒否されます):

Dir.glob('path/**/*').reject{ |e| File.directory? e }

代替ソリューション

Find#findようなパターンベースのルックアップ方法を使用するDir.glob方が実際には優れています。「Rubyでディレクトリを再帰的に一覧表示するための1行」という回答を参照してください


18

これは私にとってはうまくいきます:

隠しファイルが必要ない場合は、[1]、Dir []を使用します。

# With a relative path, Dir[] will return relative paths 
# as `[ './myfile', ... ]`
#
Dir[ './*' ].select{ |f| File.file? f } 

# Want just the filename?
# as: [ 'myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.basename f }

# Turn them into absolute paths?
# [ '/path/to/myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.absolute_path f }

# With an absolute path, Dir[] will return absolute paths:
# as: [ '/home/../home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }

# Need the paths to be canonical?
# as: [ '/home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }.map{ |f| File.expand_path f }

これで、Dir.entriesは隠しファイルを返し、ワイルドカードアスタリスクは必要ありません(変数をディレクトリ名で渡すことができます)が、ベース名を直接返すため、File.xxx関数は機能しません。 。

# In the current working dir:
#
Dir.entries( '.' ).select{ |f| File.file? f }

# In another directory, relative or otherwise, you need to transform the path 
# so it is either absolute, or relative to the current working dir to call File.xxx functions:
#
home = "/home/test"
Dir.entries( home ).select{ |f| File.file? File.join( home, f ) }

[1] .dotfileUNIXでは、Windowsについて知りません



9

個人的には、これはフォルダー内のファイルをループするのに最も便利で、前向きな安全性です。

Dir['/etc/path/*'].each do |file_name|
  next if File.directory? file_name 
end

9

これは、ディレクトリ内のファイルを検索するためのソリューションです。

files = Dir["/work/myfolder/**/*.txt"]

files.each do |file_name|
  if !File.directory? file_name
    puts file_name
    File.open(file_name) do |file|
      file.each_line do |line|
        if line =~ /banco1/
          puts "Found: #{line}"
        end
      end
    end
  end
end

6

ディレクトリ内のすべてのファイル名を取得している間、このスニペットを使用して、ディレクトリ[ ...]と、.

files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}

Dir.entries絶対ファイルパスではなく、ローカルファイル名を返します。一方、File.directory?絶対ファイルパスが必要です。このコードは期待どおりに動作しません。
Nathan

あなたのケースではコードが機能しないのは奇妙です。これは私がライブアプリで使用したコードなので、うまく機能します。私のコードを再確認し、元の作業コードに不足しているものがあればここに投稿します:)
Lahiru

1
説明のために私の答えを参照してください@Nathan


4

これは私にとってうまくいくものです:

Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }

Dir.entries文字列の配列を返します。次に、が現在の作業ディレクトリと同じFile.file?でない限り、ファイルの完全パスをに指定する必要がありますdir。これが理由File.join()です。


1
「。」を除外する必要があります。およびエントリからの「..」
エドガーオルテガ

3

Rake::FileListrake依存関係がある場合)を使用することもできます。

FileList.new('lib/*') do |file|
  p file
end

APIによると:

FileListは遅延します。ファイルリストに含まれる可能性のあるファイルのグロブパターンのリストが与えられると、ファイル構造を検索してファイルを見つける代わりに、FileListは後の使用のためにパターンを保持します。

https://docs.ruby-lang.org/en/2.1.0/Rake/FileList.html


1

symlinksを含むファイル名の配列を取得したい場合は、

Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }

あるいは

Dir.new('/path/to/dir').reject { |f| File.directory? f }

シンボリックリンクなしで移動したい場合は、

Dir.new('/path/to/dir').select { |f| File.file? f }

他の回答に示されているように、すべてのファイルを再帰的に取得する場合Dir.glob('/path/to/dir/**/*')Dir.new('/path/to/dir')、代わりにを使用してください。


または単に使用する*.*
Richard Peck


1

このスレッドでの提案に加えて、ドットファイル(.gitignoreなど)も返す必要がある場合は、Dir.globを使用してフラグを含める必要があることを述べておきます。 Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) 使用して、次のます。デフォルトでは、Dir.entries現在の親ディレクトリだけでなく、ドットファイルも含まれます。

興味のある方は、ここでの回答が実行時間で互いにどのように比較されるのかを知りました。深くネストされた階層に対する結果です。最初の3つの結果は非再帰的です。

       user     system      total        real
Dir[*]: (34900 files stepped over 100 iterations)
  0.110729   0.139060   0.249789 (  0.249961)
Dir.glob(*): (34900 files stepped over 100 iterations)
  0.112104   0.142498   0.254602 (  0.254902)
Dir.entries(): (35600 files stepped over 100 iterations)
  0.142441   0.149306   0.291747 (  0.291998)
Dir[**/*]: (2211600 files stepped over 100 iterations)
  9.399860  15.802976  25.202836 ( 25.250166)
Dir.glob(**/*): (2211600 files stepped over 100 iterations)
  9.335318  15.657782  24.993100 ( 25.006243)
Dir.entries() recursive walk: (2705500 files stepped over 100 iterations)
 14.653018  18.602017  33.255035 ( 33.268056)
Dir.glob(**/*, File::FNM_DOTMATCH): (2705500 files stepped over 100 iterations)
 12.178823  19.577409  31.756232 ( 31.767093)

これらは、次のベンチマークスクリプトで生成されました。

require 'benchmark'
base_dir = "/path/to/dir/"
n = 100
Benchmark.bm do |x|
  x.report("Dir[*]:") do
    i = 0
    n.times do
      i = i + Dir["#{base_dir}*"].select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.glob(*):") do
    i = 0
    n.times do
      i = i + Dir.glob("#{base_dir}/*").select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.entries():") do
    i = 0
    n.times do
      i = i + Dir.entries(base_dir).select {|f| !File.directory? File.join(base_dir, f)}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir[**/*]:") do
    i = 0
    n.times do
      i = i + Dir["#{base_dir}**/*"].select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.glob(**/*):") do
    i = 0
    n.times do
      i = i + Dir.glob("#{base_dir}**/*").select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.entries() recursive walk:") do
    i = 0
    n.times do
      def walk_dir(dir, result)
        Dir.entries(dir).each do |file|
          next if file == ".." || file == "."

          path = File.join(dir, file)
          if Dir.exist?(path)
            walk_dir(path, result)
          else
            result << file
          end
        end
      end
      result = Array.new
      walk_dir(base_dir, result)
      i = i + result.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.glob(**/*, File::FNM_DOTMATCH):") do
    i = 0
    n.times do
      i = i + Dir.glob("#{base_dir}**/*", File::FNM_DOTMATCH).select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
end

ファイル数の違いはDir.entries、デフォルトで隠しファイルを含めることによるものです。Dir.entriesこの場合、ファイルがディレクトリであるかどうかを判断するためにファイルの絶対パスを再構築する必要があるため、少し時間がかかりましたが、それがなくても、再帰的な場合の他のオプションよりも一貫して時間がかかっていました。これはすべてOSXでruby 2.5.1を使用していました。


1

簡単な方法の1つは次のとおりです。

dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}

files.each do |f|
    puts f
end

0
def get_path_content(dir)
  queue = Queue.new
  result = []
  queue << dir
  until queue.empty?
    current = queue.pop
    Dir.entries(current).each { |file|
      full_name = File.join(current, file)
      if not (File.directory? full_name)
        result << full_name
      elsif file != '.' and file != '..'
          queue << full_name
      end
    }
  end
  result
end

ディレクトリとすべてのサブディレクトリからファイルの相対パスを返します


0

IRBコンテキストでは、次を使用して現在のディレクトリ内のファイルを取得できます。

file_names = `ls`.split("\n")

これを他のディレクトリでも機能させることができます:

file_names = `ls ~/Documents`.split("\n")

Dir.childrenコマンドをサポートしない古いルビーバージョンのレガシーソリューションがあるため、このソリューションは私にとってうまくいきました
Ciprian Dragoe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.