【问题标题】:Iterate through every file in one directory遍历一个目录中的每个文件
【发布时间】:2011-01-31 12:28:23
【问题描述】:

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

我是 ruby​​ 新手,我得出的结论是这样做的方法是每个循环。
ruby 文件将从与我要循环的目录不同的目录中执行。

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

【问题讨论】:

  • 你能具体说明当你试图让它工作时发生了什么吗?您尝试了哪些确切的代码(或相关的块,如果它很长)?您收到了哪些错误消息? Dir.foreach 用于迭代目录的内容,所以还有很多事情要做。
  • 如果您只想要目录中的文件,请不要忘记在遍历目录内容时测试文件:do_something_with(entry) if File.file?(entry)
  • 使用'img/*.{jpg,png,gif,jpeg}' 抓取多个扩展。
  • 不幸的是,@ChrisPeters 似乎不太可能,因为 OP 已经四年多没有出现在该网站上了。

标签: ruby directory filesystems


【解决方案1】:

正如其他人所说,Dir::foreach 是一个不错的选择。但是,请注意Dir::foreachDir::entries 将始终包括...(当前目录和父目录)。您通常不想处理它们,因此您可以使用Dir::each_childDir::children(如suggested by 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

【讨论】:

  • 如果目录包含大量文件,请使用Dir.foreach
  • 谢谢!让它变得更好的小模组:next if File.directory? item
  • @mr.buttons 这并不总是正确的。有时人们希望处理目录 以及文件。我给出了避免 ... 的特殊列表的代码,因为人们几乎总是想忽略这两个。
  • @Tilo:只是出于兴趣,想详细解释一下为什么? :)
  • @mkataja Dir.foreach 迭代而不是在前面建立一个(可能很大的)数组(Dir.glob 确实如此)。因此,如果目录真的很大,它会产生性能差异。在正常情况下您不会注意到,但在压力条件下,这绝对很重要。
【解决方案2】:

要跳过...,您可以使用Dir::each_child

Dir.each_child('/path/to/dir') do |filename|
  puts filename
end

Dir::children 返回文件名数组。

【讨论】:

    【解决方案3】:

    find 库是专门为这个任务设计的: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

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

    这是一个标准的 ruby​​ 库,所以它应该是可用的

    【讨论】:

    • File.find 尽可能递归地向下,从你给它的任何路径开始。我不确定这是 OP 想要的。
    • 我似乎无法使用该方法 - Find.find ?我是否需要下载包含此功能的库?
    • @user470184:“Find”是一个标准的 ruby​​ 库,应该在默认的 ruby​​ 安装中可用。但是,您需要“要求 'find'”才能使用它。
    • @Faisal 我可以将像*.rb 这样的全局模式传递给find()
    【解决方案4】:

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

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

    好处是你得到一个路径名对象而不是一个字符串,你可以用它做有用的东西并进一步遍历。

    【讨论】:

      【解决方案5】:

      Dir 还有更短的语法来从目录中获取所有文件的数组:

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

      【讨论】:

      • 这段代码中的什么阻止了目录也被fname的迭代使用?
      【解决方案6】:

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

      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
      

      【讨论】:

        【解决方案7】:
        Dir.new('/my/dir').each do |name|
          ...
        end
        

        【讨论】:

        • 除了 Dir.new('/my/dir') 还有 Dir.entries('/my/dir') 但 Dir.foreach() 更简洁一些。
        • @Z.E.D.同样Dir.foreach 迭代,而Dir.entries 一次构建整个数组。因此,如果目录很大,则内存不足。 (通常没什么大不了的,可能,但仍然......)
        【解决方案8】:
        Dir.foreach("/home/mydir") do |fname|
          puts fname
        end
        

        【讨论】:

        • 或者使用 Dir#[] 或 Dir#glob
        猜你喜欢
        • 1970-01-01
        • 2021-01-16
        • 1970-01-01
        • 2019-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-29
        • 2020-10-22
        相关资源
        最近更新 更多