使用Ruby获取文件夹中所有文件的名称

432

我想使用Ruby从一个文件夹中获取所有文件名。

19个回答

6
这是我使用的方法:

这是我使用的方法:

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

Dir.entries 返回一个字符串数组。然后,我们必须提供文件的完整路径给 File.file?,除非 dir 等于我们当前的工作目录。这就是为什么要使用 File.join()


1
你需要从条目中排除“.”和“..”。 - Edgar Ortega
1
这个答案是重复的,与2013年添加的答案相同。 - Hirurg103

3

您可能还想使用Rake::FileList(前提是您已经安装了rake依赖):

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

根据API:
文件列表是惰性的。当给出一系列可能包含在文件列表中的glob模式时,文件列表不会搜索文件结构以查找文件,而是保留该模式供后续使用。

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


3
一种简单的方法可能是:
dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}

files.each do |f|
    puts f
end

3
Dir.new('/home/user/foldername').each { |file| puts file }

2
除了本主题中的建议,我想提一下如果您需要返回点文件(.gitignore等),使用Dir.glob时您需要包含一个标志,如下所示: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) 默认情况下,Dir.entries包括点文件以及当前和父目录。
对于任何感兴趣的人,我很好奇这里的答案在执行时间上相互比较,以下是针对深度嵌套层次结构的结果。前三个结果是非递归的:
       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进行的。

2
当加载操作目录中的所有文件名时,您可以使用

Dir.glob("*)

这将返回应用程序运行环境中的所有文件(对于Rails来说,这是应用程序的顶层目录)。
您可以进行额外的匹配和递归搜索,具体请参见https://ruby-doc.org/core-2.7.1/Dir.html#method-c-glob

1
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

从目录及其所有子目录返回文件的相对路径

1
如果您想获取包括符号链接的文件名数组,请使用:
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

0

如果你用空格创建文件夹:

mkdir "a b"
touch "a b/c"

您不需要转义目录名称,它会自动完成:

p Dir["a b/*"] # => ["a b/c"]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接