ADL
ADL

Reputation: 185

How do I open each file in a directory with Ruby?

I need to open each file inside a directory. My attempt at this looks like:

Dir.foreach('path/to/directory') do |filename|
  next if filename == '.' || filename == '..'
  puts "working on #{filename}"

  # this is where it crashes
  file = File.open(filename, 'r')

  #some code

  file.close

  # more code

end

My code keeps crashing at File.open(filename, 'r'). I'm not sure what filename should be.

Upvotes: 2

Views: 4222

Answers (3)

Pascal
Pascal

Reputation: 8637

I'd go for Dir.glob or File.find. But not Dir.foreach as it returns . and .. which you don't want.

Dir.glob('something/*').each do |filename|
  next if File.directory?(filename)
  do_something_with_the_file(filename)
end

Upvotes: 2

the Tin Man
the Tin Man

Reputation: 160551

I recommend using Find.find.

While we can use various methods from the Dir class, it will look and retrieve the list of files before returning, which can be costly if we're recursively searching multiple directories or have a huge number of files embedded in the directories.

Instead, Find.find will walk the directories, returning both the directories and files as each is found. A simple check lets us decide which we want to continue processing or whether we want to skip it. The documentation has this example which should be easy to understand:

The Find module supports the top-down traversal of a set of file paths.

For example, to total the size of all files under your home directory, ignoring anything in a “dot” directory (e.g. $HOME/.ssh):

require 'find'

total_size = 0

Find.find(ENV["HOME"]) do |path|
  if FileTest.directory?(path)
    if File.basename(path)[0] == ?.
      Find.prune       # Don't look any further into this directory.
    else
      next
    end
  else
    total_size += FileTest.size(path)
  end
end

Upvotes: 2

spickermann
spickermann

Reputation: 106802

The filename should include the path to the file when the file is not in the same directory than the Ruby file itself:

path = 'path/to/directory'
Dir.foreach(path) do |filename|
  next if filename == '.' || filename == '..'

  puts "working on #{filename}"

  file = File.open("#{path}/#{filename}", 'r')

  #some code

  file.close

  # more code
end

Upvotes: 4

Related Questions