遍历一个目录中的每个文件


274

如何在ruby中编写循环,以便可以在每个文件上执行代码块?

我是红宝石的新手,我已经得出结论,做到这一点的方法是每次循环。
ruby文件将从与我要循环访问的目录不同的目录执行。

我已经尝试过了Dir.foreach,但无法正常工作。


2
您能否指定尝试使其工作时发生了什么?您尝试了什么确切的代码(或者相关的块,如果很长的话)?您收到什么错误消息?Dir.foreach用于遍历目录的内容,因此还有很多其他事情要做。
Telemachus

3
如果只希望目录中的文件,请在遍历目录内容时不要忘记测试文件: do_something_with(entry) if File.file?(entry)
glenn jackman 2010年

3
使用'img/*.{jpg,png,gif,jpeg}'抓取多个扩展。
本杰明·克鲁兹耶

不幸的是,@ ChrisPeters似乎不太可能,因为OP已有四年没有出现在网站上了。
乔·肯尼迪

Answers:


429

正如其他人所说,这Dir::foreach是一个不错的选择。但是,请注意,Dir::foreachand Dir::entries将始终包括.and ..(当前目录和父目录)。通常,您将不希望对其进行任何操作,因此可以使用Dir::each_childDir::children(如ma11hew28的建议)或执行以下操作:

Dir.foreach('/path/to/dir') do |filename|
  next if filename == '.' or filename == '..'
  # Do work on the remaining files & directories
end

Dir::foreachDir::entries(以及Dir::each_childDir::children)还包括隐藏的文件和目录。通常这是您想要的,但是如果不是,则需要做一些事情来跳过它们。

另外,您可能想看看Dir::glob其中提供了简单的通配符匹配:

Dir.glob('/path/to/dir/*.rb') do |rb_filename|
  # Do work on files & directories ending in .rb
end

12
使用Dir.foreach如果该目录包含文件的数量巨大!
2013年

5
谢谢!小型mod使其变得更好:next if File.directory? item
Buttons先生

@ mr.buttons不会总是做正确的事。有时人们想同时处理目录和文件。我给出了避免使用特殊代码的代码,.或者..因为人们几乎总是想忽略这两个代码。
Telemachus,2015年

3
@Tilo:只是出于兴趣,不妨详细解释为什么?:)
mkataja 2015年

11
@mkataja Dir.foreach迭代而不是在前面建立一个(可能巨大的)数组(Dir.glob确实如此)。因此,如果目录确实很大,则可以提高性能。在正常情况下,您不会注意到,但是在压力条件下,这绝对重要。
Telemachus 2015年

99

这是我最喜欢的易于阅读的方法:

Dir.glob("*/*.txt") do |my_text_file|
  puts "working on: #{my_text_file}..."
end

而且,您甚至可以扩展它以使其适用于子目录中的所有文件:

Dir.glob("**/*.txt") do |my_text_file| # note one extra "*"
  puts "working on: #{my_text_file}..."
end

30

Dir的语法也较短,可以从目录中获取所有文件的数组:

Dir['dir/to/files/*'].each do |fname|
    # do something with fname
end

这段代码中有什么阻止目录也用于fname的迭代?
kayleeFrye_onDeck


13

查找库专门用于此任务:https : //ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

require 'find'
Find.find(path) do |file|
  # process
end

这是一个标准的ruby库,因此应该可用


1
File.find从您提供的任何路径开始,尽可能递归地向下移动。我不确定这是OP想要的。
Telemachus

我似乎无法访问该方法-Find.find?我是否需要下载包含此功能的库?
蓝天

@ user470184:“查找”是一个标准的ruby库,默认安装的ruby应该可用。但是,您需要先“要求'查找'”,然后才能使用它。
Faisal

1
@Faisal我可以通过glob模式一样*.rb,以find()
Ashhar哈桑

7

我喜欢这个,上面没有提到。

require 'pathname'

Pathname.new('/my/dir').children.each do |path|
    puts path
end

好处是您得到的是路径名对象而不是字符串,您可以使用它进行有用的操作并进一步遍历。


3
Dir.new('/my/dir').each do |name|
  ...
end

1
除了Dir.new('/ my / dir')外,还有Dir.entries('/ my / dir'),但Dir.foreach()更为简洁。
Tin Man 2010年

5
@ZED同时Dir.foreach迭代,同时一次Dir.entries构建整个数组。因此,如果目录很大,那么它对内存的影响就更少了。(通常可能没什么大不了,但仍然...)
Telemachus

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.