Get names of all files from a folder with Ruby

后端 未结 19 2193
[愿得一人]
[愿得一人] 2020-11-29 14:57

I want to get all file names from a folder using Ruby.

相关标签:
19条回答
  • 2020-11-29 15:52

    In addition to the suggestions in this thread, I wanted to mention that if you need to return dot files as well (.gitignore, etc), with Dir.glob you would need to include a flag as so: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) By default, Dir.entries includes dot files, as well as current a parent directories.

    For anyone interested, I was curious how the answers here compared to each other in execution time, here was the results against deeply nested hierarchy. The first three results are non-recursive:

           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)
    

    These were generated with the following benchmarking script:

    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
    

    The differences in file counts are due to Dir.entries including hidden files by default. Dir.entries ended up taking a bit longer in this case due to needing to rebuild the absolute path of the file to determine if a file was a directory, but even without that it was still taking consistently longer than the other options in the recursive case. This was all using ruby 2.5.1 on OSX.

    0 讨论(0)
  • 2020-11-29 15:53
    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
    

    returns file's relative paths from directory and all subdirectories

    0 讨论(0)
  • 2020-11-29 15:53

    When loading all names of files in the operating directory you can use

    Dir.glob("*)

    This will return all files within the context that the application is running in (Note for Rails this is the top level directory of the application)

    You can do additional matching and recursive searching found here https://ruby-doc.org/core-2.7.1/Dir.html#method-c-glob

    0 讨论(0)
  • 2020-11-29 15:55

    You also have the shortcut option of

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

    and if you want to find all Ruby files in any folder or sub-folder:

    Dir["/path/to/search/**/*.rb"]
    
    0 讨论(0)
  • 2020-11-29 15:55

    To get all files (strictly files only) recursively:

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

    Or anything that's not a directory (File.file? would reject non-regular files):

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

    Alternative Solution

    Using Find#find over a pattern-based lookup method like Dir.glob is actually better. See this answer to "One-liner to Recursively List Directories in Ruby?".

    0 讨论(0)
  • 2020-11-29 15:57
    Dir.entries(folder)
    

    example:

    Dir.entries(".")
    

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

    0 讨论(0)
提交回复
热议问题