2011-11-02 28 views
9

我是Ruby新手(作为Java开发人员)并试图实现一种方法(哦,对不起,一个函数),它将递归检索并产生子目录中的所有文件。Ruby中的递归文件列表

我实现它:

def file_list_recurse(dir) 
    Dir.foreach(dir) do |f| 
    next if f == '.' or f == '..' 
    f = dir + '/' + f 
    if File.directory? f 
     file_list_recurse(File.absolute_path f) { |x| yield x } 
    else 
     file = File.new(f) 
     yield file 
    end 
    end 
end 

我的问题是:

  1. 不File.new真正打开一个文件?在Java新的文件(“xxx”)不......如果我需要产生一些结构,我可以查询文件信息(ctime,大小等)从它将在Ruby中会是什么?
  2. {| x | yield x}对我来说看起来有点奇怪,是否可以通过类似递归函数来产生收益,还是有一些方法可以避免它?
  3. 有没有办法避免检查'。'和'..'在每次迭代?
  4. 有没有更好的方法来实现这个?

感谢

PS: 我的方法的示例用法是这样的:

curr_file = nil 

file_list_recurse('.') do |file| 
    curr_file = file if curr_file == nil or curr_file.ctime > file.ctime 
end 

puts curr_file.to_path + ' ' + curr_file.ctime.to_s 

(这将让你从树上最早的文件)

= =========

所以,感谢@buruza埃蒙我发现了伟大的Dir.glob函数,它为我节省了几行代码。 此外,由于@Casper我发现了File.stat方法,这使我的功能运行比File.new

快两倍到底我的代码看起来像这样:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 

=====

默认Dir.glob忽略文件名开头的一个点(认为* nix中被“隐藏”),所以要加第二个参数文件是非常重要:: FNM_DOTMATCH

回答

5

这件事情告诉我考虑接受一个答案,我希望它不会介意我回答我自己:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 
2

您可以使用内置的Find模块的find方法。

11

这个怎么样?

puts Dir['**/*.*'] 
+0

这是伟大的!但它会产生一个String对象数组。我在寻找的是一个函数,它会产生一个类似于文件的结构,以便我可以根据它进行自己的计算。找到最大的文件,最早的ctime等。 –

+0

Dir ['。']不接受一个块。但是Dir.glob呢!它回答我的问题,除了#1问题 –

5

根据文档File.new打开文件。您可能需要使用File.stat,它将与文件相关的统计信息收集到可查询对象中。但请注意,统计信息是在创建点收集的。当您调用类似ctime的查询方法时,不是。

例子:

Dir['**/*'].select { |f| File.file?(f) }.map { |f| File.stat(f) } 
+1

File.stat具有讽刺意味的是不提供文件的名称,所以我不能用它作为数据对象从我的方法返回。 另外,我有一个200,000个文件的树。 运行您的示例结果在ruby进程增长超过60 Mb,同时运行我的方法(即使使用File.new)永远不会让红宝石超过6 Mb。 (我正在测试-n 0,1“ps ax -o comm,rss | grep ruby​​ >>/tmp/q”)。 但你样品代码的行确实看起来很酷;-) –