如何在文件夹及其所有子文件夹中搜索某种类型的文件


70

我正在尝试在给定文件夹中搜索给定类型的所有文件,并将它们复制到新文件夹中。

我需要指定一个根文件夹,并在该文件夹及其所有子文件夹中搜索与给定类型匹配的所有文件。

如何搜索根文件夹的子文件夹及其子文件夹?似乎可以使用递归方法,但是我无法正确实现一个方法。

Answers:


64

您需要查找模块。Find.find接受包含路径的字符串,并将父路径以及每个文件和子目录的路径传递到随附的块。一些示例代码:

require 'find'

pdf_file_paths = []
Find.find('path/to/search') do |path|
  pdf_file_paths << path if path =~ /.*\.pdf$/
end

这将递归搜索路径,并将所有以.pdf结尾的文件名存储在数组中。


116

尝试这个:

Dir.glob("#{folder}/**/*.pdf")

这与

Dir["#{folder}/**/*.pdf"]

文件夹变量是您要搜索的根文件夹的路径。


3
我认为OP想要递归,不是吗?
rogerdpack

2
@rogerdpack据我了解,此方法是递归的。答案实际上应该是Dir.glob("#{folder}/**/*.pdf"),其中folder变量是您要搜索的根文件夹的路径。
Automatico

1
默认情况下
也不

2
@Konstantin这Dir#[]就是我通常使用的。但是,有一个陷阱:Dir.glob将所有路径都加载到内存中。通常这很好,但是如果您有很多路径,则可能更喜欢使用Find模块,因为它会在找到路径时将路径传递给块。
韦恩·康拉德

2
我对此同意@WayneConrad。您可能会由于Ruby分配足够的内存来存储大数组而无意中止了程序。这与为文件加注非常相似。让Find处理层次结构而不是将其扔到OS上可能会得到意外的数组,这样效率更高,并且可能更快。调试这种情况很困难。
锡人

27

如果速度是一个问题,更喜欢Dir.globFind.find

Warming up --------------------------------------
           Find.find   124.000  i/100ms
            Dir.glob   515.000  i/100ms
Calculating -------------------------------------
           Find.find      1.242k (± 4.7%) i/s -      6.200k in   5.001398s
            Dir.glob      5.249k (± 4.5%) i/s -     26.265k in   5.014632s

Comparison:
            Dir.glob:     5248.5 i/s
           Find.find:     1242.4 i/s - 4.22x slower

 

require 'find'
require 'benchmark/ips'

dir = '.'

Benchmark.ips do |x|
  x.report 'Find.find' do
    Find.find(dir).select { |f| f =~ /\*\.pdf/ }
  end

  x.report 'Dir.glob' do
    Dir.glob("#{dir}/**/*\.pdf")
  end

  x.compare!
end

使用 ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin15]


2
谢谢你的帖子。对于像我这样的初学者来说,找出在Dir.globvs中应该使用哪种方法非常有帮助Find.find
itsh 2013年

5
在这种情况下,查找应该变慢,因为您正在使用正则表达式查找。另一方面,Dir.glob不如正则表达式那么强大,因此我希望它会更快。
hirowatari

我想您可以#end_with?用来比较它们之间的关系
。...– rogerdpack

1
@hirowatari正则表达式与否无关紧要-您可以用替换整个块内容,false但它仍然会显着变慢(尝试一下)。这是因为调用块也需要一些时间,并且对于找到的每个项目都会发生,而glob内部过滤器只有在完成收集结果后才会返回。因此,与之配合使用的过滤器find可能非常复杂,可能是包含查找和多个正则表达式的100行代码,而glob每个调用只了解一种简单的模式。如果您可以通过这种方式表示搜索,请选择glob
麦基

但是,如果您实际上必须对这些文件执行某些操作,则将需要为每个文件调用某些内容。因此,根据用例进行比较可能不公平。同样对于巨大的目录树,人们可能不想将整个数组存储在内存中。所以有时候一个会更好,而另一个会更好。
akostadinov

12

作为对Jergason和Matt上面回答的一个小改进,这是您可以压缩为一行的方法:

pdf_file_paths = Find.find('path/to/search').select { |p| /.*\.pdf$/ =~ p }

这使用上面的Find方法,但是利用了结果是可枚举的事实(因此我们可以使用select)来获取具有匹配集的数组


0

另一种快速的方法是将任务委托给shell命令“ find”并分割输出:

pdf_file_paths = `find #{dir} -name "*.pdf"`.split("\n")

在Windows上不起作用。

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.