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


Answers:


537

您还具有以下快捷方式选项:

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

如果要在任何文件夹或子文件夹中找到所有Ruby文件,请执行以下操作:

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

5
或者,您也可以使用Dir :: glob()做同样的事情
Yoann Le Touche,2009年

2
此外,请使用./...而不是~/
Minh Triet,2014年

5
为什么偏爱这个?
BvuRVKyUVlViVIc7

1
@MinhTriet是做什么的?最好是什么?
stephenmurdoch 2015年

9
@marflar- ./表示当前目录,而是/根挂载点,并且~/是用户的主目录。如果将整个项目移到其他位置,则第一个项目将起作用,而其他两个项目可能不会起作用。
mirichan

170
Dir.entries(folder)

例:

Dir.entries(".")

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


15
看起来他正在使用SO记录他刚刚问的问题的答案。我想是一种备忘录。对此看不出什么大错-毕竟,即使这个问题有些不完整(Dir#glob例如,也许有人提到过),也没有什么可以阻止其他人发布“真正的好答案”。'当然,我主要是个“半杯”的家伙……
Mike Woodhouse

1
@迈克:在宏伟的计划中,这可能没什么大不了的。正如您所说的那样,如果问题和答案都不错,那么对于该网站而言可能是个加分项。但是这里的问题和答案都非常小,以至于它似乎没有什么用处。
Telemachus

17
@Telemachus我Dir很少使用,每次需要时,我都必须阅读文档。我在这里发布了我的问题和答案,以便以后找到,甚至可以帮助遇到相同问题的人。我想我在SO播客上听说过,这种行为没有任何问题。如果您有更好的答案,请发布。我已经发布了我所知道的信息,我不是Ruby忍者。我经常接受票数最高的答案。
泽利科菲

这比一个更好的选择,Dir[]或者Dir.glob当参数是一个变量。什么时候path = '/tmp'比较: Dir.glob("#{path}/*")vs Dir.entries(path)。返回值略有不同(“。”,“ ..”),但是快速浏览后一个值比较容易。
本杰明·奥克斯

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?没有。
卡米尔·莱洛内克

2
@squixy我有同样的问题,在我来说,我需要提供完整的路径不只是文件名返回的Dir.foreach
TheLukeMcCarthy

6
.reject {|f| File.directory? f}似乎比.select{|f| !File.directory? f}。哦,现在我看到第一个评论了……也很好。
伊恩


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] .dotfile在UNIX上,我不了解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?期望绝对文件路径。此代码无法正常工作。
内森

奇怪的是,代码在您的情况下不起作用。因为这是我在实时应用程序中使用过的代码,所以效果很好。如果我的原始工作代码中缺少任何内容,我将重新检查我的代码并发布在这里:)
Lahiru

1
@Nathan请参阅我的答案以获取解释


4

这对我有用:

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

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


1
您需要排除“。” 和条目中的“ ..”
Edgar Ortega,


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')如果要递归获取所有文件,请使用代替。


或者只是使用*.*
理查德·派克


1

除了该线程中的建议外,我想提到的是,如果您还需要返回点文件(.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。



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
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.