Iterate through every file in one directory

2019-01-08 03:44发布

问题:

How do I write a loop in ruby so that I can execute a block of code on each file?

I'm new to ruby, and I've concluded that the way to do this is a do each loop.
The ruby file will be executed from a different directory than the directory I want to loop through.

I've tried the Dir.foreach and I couldn't get it to work.

回答1:

As others have said, Dir.foreach is a good option here. However, note that Dir.entries and Dir.foreach will always show . and .. (the current and parent directories). You will generally not want to work on them, so you can do something like this:

Dir.foreach('/path/to/dir') do |item|
  next if item == '.' or item == '..'
  # do work on real items
end

Dir.foreach and Dir.entries also show all items in the directory - hidden and non-hidden alike. Often this is what you want, but if it isn't, you need to do something to skip over the hidden files and directories.

Alternatively, you might want to look into Dir.glob which provides simple wildcard matching:

Dir.glob('/path/to/dir/*.rb') do |rb_file|
  # do work on files ending in .rb in the desired directory
end


回答2:

This is my favorite method for being easy to read:

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

And you can even extend this to work on all files in subdirs:

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


回答3:

Dir has also shorter syntax to get an array of all files from directory:

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


回答4:

Dir.foreach("/home/mydir") do |fname|
  puts fname
end


回答5:

The find library is designed for this task specifically: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

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

This is a standard ruby library, so it should be available



回答6:

I like this one, that hasn't been mentioned above.

require 'pathname'

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

The benefit is that you get a Pathname object instead of a string, that you can do useful stuff with and traverse further.



回答7:

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