【问题标题】:recursive file list in RubyRuby中的递归文件列表
【发布时间】:2011-11-02 16:06:28
【问题描述】:

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

我已将其实现为:

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 中 new File("xxx") 不...如果我需要产生一些结构,我可以从 Ruby 中查询文件信息(ctime、大小等)?
  2. { |x| yield x } 对我来说看起来有点奇怪,从这样的递归函数中进行 yield 是否可以,或者有什么方法可以避免它?
  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

(这将使您获得树中最旧的文件)

==========

所以,感谢@buruzaemon,我发现了很棒的 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 中被视为“隐藏”),因此添加第二个参数 File::FNM_DOTMATCH 非常重要

【问题讨论】:

    标签: ruby file recursion


    【解决方案1】:

    这个怎么样?

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

    【讨论】:

    • 太好了!但它会产生一个字符串对象数组。我正在寻找的是能够产生类似文件结构的函数,以便我可以根据它进行自己的计算。查找最大的文件、最早的 ctime 等。
    • Dir['.'] 不接受块。但是 Dir.glob 可以!它回答了我的问题,除了问题 #1
    【解决方案2】:

    根据文档File.new 确实打开了文件。您可能想改用File.stat,它将与文件相关的统计信息收集到可查询的对象中。但请注意,统计数据是在创建时收集的。不是当你调用像ctime这样的查询方法时。

    例子:

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

    【讨论】:

    • File.stat 具有讽刺意味的是没有提供文件的名称,所以我不能将它用作从我的方法返回的数据对象。另外,我有一棵包含 200,000 个文件的树。运行您的示例导致 ruby​​ 进程增长到 60 Mb 以上,而运行我的方法(即使使用 File.new)永远不会使 ruby​​ 超过 6 Mb。 (我正在使用 watch -n 0,1 "ps ax -o comm,rss|grep ruby​​ >> /tmp/q" 进行测试)。但是您的示例代码行确实看起来很酷;-)
    【解决方案3】:

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

    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}"
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        如果您使用的是 Windows,请在此处查看我的答案,以获得比标准 Ruby Dir 更快(约 26 倍)的方式。如果您使用 mtime,它仍然会更快。

        如果您使用其他操作系统,您可以使用相同的技术,我很好奇收益是否会那么大,但我几乎可以肯定。

        How to find the file path of file that is not the current file in ruby

        【讨论】:

          猜你喜欢
          • 2018-10-07
          • 1970-01-01
          • 1970-01-01
          • 2018-03-05
          • 1970-01-01
          • 2013-12-10
          • 1970-01-01
          • 2016-07-30
          • 2011-01-04
          相关资源
          最近更新 更多