Ruby for Newbies: Working with Directories and Files
videos

Ruby for Newbies: Working with Directories and Files

Tutorial Details
  • Topic: Ruby
  • Difficulty: Beginner - Intermediate
  • Format: Video
This entry is part 7 of 13 in the Ruby for Newbies Session
« PreviousNext »

Ruby is a one of the most popular languages used on the web. We’ve recently started a new Session here on Nettuts+ that will introduce you to Ruby, as well as the great frameworks and tools that go along with Ruby development. Today, we’ll look at the Dir and File classes, and how we can use them to work with directories and files.

 


View Screencast

Press the HD button for a clearer video.
Alternate Viewing Source

Directories

pwd

If you’ve done much work with the terminal (AKA command line, AKA shell), you’ll know that it has the notion of a current directory, called the working directory. This is the folder you are currently in. Whenever you type a command that uses a file, the working directory will be the first place your shell looks to find the file.

Ruby has a similar notion when executing code. It understands the OS’s folder structure, and has some helpful tools for working with it.

So, how do you find out what folder you’re ruby script thinks it is in?

Dir.pwd # "/Users/andrew/Documents" 

The pwd (print working directory) method on the Dir class gives us that information. If you’re in irb, your working directory will be—by default—the folder you started irb in. If you’re in a script, will be the location you’re calling the script from.

chdir

If you want to change the working directory, you can use the chdir method; pass it the path to the directory you want to move to:

Dir.chdir "Documents"

Dir.chdir "/users/andrew/Documents"

As you can see, the string parameter can be either an absolute or a relative path.

glob

If you’re looking for certain files within the working directory (Dir.pwd), you can get them by using the Dir.glob method. Pass that method a “glob”; that’s a search pattern that’s somewhere between a static string and a full regular expression. You can use an asterisk * as a wildcard, just as you might in the shell; you can use a double asterisk ** to match directories recursively. You can also use sets in square brackets as you would with regular expressions. If you need more, check out the full docs. Dir.glob with return an array … or, you can pass it a block and get each match one by on.

# Remember, this runs on the current directory
all_text_files = Dir.glob "*.txt"

Dir.glob("**/*.[a-z]") do |filename|
    # will match any file in any child directory with a single lower-case letter extension
end

new & open

Besides housing useful functions, you can also make an instance of the Dir class. You pass it the name of the directory you want to use; as with all functions that take a path, it can be absolute or relative.

reciepts = Dir.new "reciepts"
me = Dir.open "/users/andrew"

Both new and open return a Dir object; however, there’s another way to use open:

Dir.open "/users/andrew" do |dir|
    # use it here
end

This is a common convention with many classes in Ruby; instead of storing the Dir object in a variable, you can pass it to a block and use it from in there. It’s a pretty different style of coding that I haven’t seen in any other language, but it’s rather nice only you get used to it.

There’s a good chance that when you create a Dir object, you’ll want to work with the contents of it. There are a few ways to do that.

each

Assuming some_dir is Dir object,

some_dir.each do |file|
    # do something
end

You can use the each method on Dir objects to iterate over each file or directory that is inside it. Note that you’re not getting a File or Dir object; just a string with the name of it; if you want to do more, you’ll have to instantiate the appropriate object yourself.

entries

If you just want to see what’s inside a directory, you can use the entries property, to get an array of the contents:

some_dir.entries # [ ".", "..", "file_one.txt", "another_directory"]

As you’ll note above, the entires for a directory include ”.” and “..”, pointer it itself and its parent directory.


Files

Ruby also offers a helpful API for working with files.

absolute_path

When you’re working with files, you may find yourself wanting to get the absolute path of one. The File class offers exactly what you need:

File.absotule_path "plans.txt" # => "/users/andrew/Documents/plans.txt"

basename

But what about the other way around? You’ve got the absolute path, and you want just the filename? Instead, use basename

File.basename("/users/andrew/Documents/plans.txt") # => "plans.txt"

File.basename("/users/andrew/Documents/plans.txt", ".txt") # => "plans"

If you pass a second string parameter, the method will look for that string at the end of the file name, and remove it if it is there; this doesn’t have to be the file extension, but that’s the obvious main use for this.

delete

The obvious use of this is to delete the file you pass into the method:

File.delete "code.rb"

directory?

This is a useful one; say you’re each-ing over the entries of a Dir object, but you only want to deal with files. The File.directory? method will return true if the string parameter you pass to it is a directory, and false if it’s a file.

Dir.open(Dir.pwd).each do |filename|
    next if File.directory? filename

    # otherwise, process file
end

This snippet opens the current directory and passes a block to the each method. The each method passes the entries of directory one by one to the block. That first line inside the block may confuse you a bit if you’re not used to Ruby, but look at it carefully. The only part you aren’t familiar with is the next keyword, which skips the rest of the block and goes to the next iteration of it. So, we’re saying, “skip to the next entry if the entry we currently have is a directory. If it’s not a directory, we can do whatever we want to.

new & open

Making instances of the File class works just the same as with Dir; File.new returns a File object, while File.open can return it, or pass it to a block. You should also pass a second parameter, which decides how the file will be opened. Most of the time, you’ll probably use these:

  • ”r” : read-only
  • ”w” : write-only (overwrites anything in the file, if the file exists)
  • “w+” : read and write (overwrites anything in the file, if the file exists)
  • ”a” : write-only (starts at the end of the file, if the file exists)

So, what methods does an instance of File give you? Well, these methods actually come from the IO class, from which File inherits. Most of the time, you’ll be opening a file to read or write content from it, so let’s look at that functionality.

Reading

Before we get started, remember this: the way a file works, once a line has been read, it doens’t show up again; you’re working your way through the file. At any point, you can use the f.rewind method to go back to the beginning of the file.

If you want to just read the whole thing, you can do so with read.

f = File.open("sample.txt", "r") # assume this file for the next couple of snippets

f.read # => "something\nline 2\na third\nfour!\n5555\nsixy\nsevenly\neight" 

However, you’ll probably want to read one line at a time; to do that, use the method readline:

f.rewind # back at the beginning

f.readline # "something\n"

f.readline # "line 2\n"

f.readline # "a third\n"

You could also use the method gets instead of readline.

There’s also a readlines method, which returns an array in which the lines as entries:

f.rewind

f.readlines # => ["something\n", "line 2\n", "a third\n", "four!\n", "5555\n", "sixy\n", "sevenly\n", "eight"] 

Finally, you can use each, and pass a block to the method to work with each line, one by one

f.rewind

f.each do |line|
    puts line
end

Writing

For writing, you’ve got two options: write and puts. The main difference is that puts adds a line break to the end of your string, while write does not.

f = File.open("file.txt", "w+")

f.puts "first line"
f.write "second "
f.write "line"

f.rewind

f.readlines # => ["first line\n", "second line"]

Question for You

Well, that’s it for Ruby For Newbies, Lesson 7. There’s more to discover in the Dir and File classes; check out the docs for Dir, File, and IO for more (the IO class is where File inherits its instance methods from).

However, I’m curious about where you want this series to go from here: do you want to continue with the Ruby language, or do you want to move towards using Ruby on the web? Both directions will be valuable to you as a web developer, so voice your opinion in the comments!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.nilspedersen.dk Nils Pedersen

    There are som strange echo in the voice starting from 3 minutes…
    - But else good tuts. Thanks

  • http://www.none.com.ua none

    My answer: Ruby language (-:
    Thanx!

  • http://jimneath.org Jim Neath

    There is also shorthand for Dir#glob:

    Dir["*.txt"] is the same as Dir.glob(“*.txt”)

  • Joakim Runeberg

    I’d definitely like to see a move towards Rails 3 in these tutorials

  • Dennis Carlsson

    I would love the series to go more towards the web. The core is good to know but I think we here want to do webby things with ruby in the future.
    Also don’t you get a lot of the core when you’re exploring the web bits of ruby?

  • http://oidc.com Kyle Beltram

    File.absotule_path should probably read File.absolute_path

    ;)

  • http://paninkognito.blogspot.com/ Droid

    Ruby on the web, please :-)

    • http://tutorial-city.net/ Eduardo Matos

      These techniques can also be used on the web to create log files for instance. Just think outside the box ;)

  • Myke

    Nice video. I would like to see Ruby on the web.
    Funny vox effect on the video too ^_^

  • Kevin

    You don’t seem to close any files you open. Is this not important?

    Thanks!

    • http://andrewburgess.ca Andrew Burgess
      Author

      Excellent Catch! I missed this because, most of the time in Ruby, you’ll read or write to a file using a block in the method call. When you do this, Ruby automatically closes the file for you. However, if you prefer to put the file object in a variable (say, f), you should call

      f.close

      when you’re finished with the file.

  • angel

    I could like ruby on the web too..but please no more rails!! ruby is much more than rails…….

  • http://www.apergy.co.uk Richard Edwards

    I am finding this series very interesting, I think it would perhaps be very beneficial to perhaps work on building a web application using the things we have learned so far plus more. It would not only give us insight into how the language works but also the workflow of dealing with such an OOP language.

    Thumbs up on a fantastic 7 video tutorials so far, but the last one had some sort of echo problem – no biggy though. Keep up the good work.

  • http://www.ecustom.ca/ Damon Bridges

    Hey Andrew!

    Very timely tutorial for me! Some of my friends and I have recently set out on a “2 Weeks of Ruby,” in which we take two weeks and just immerse ourselves in the language. As we progress, we each set a small project to do, and for each project we take a day or two to write a Ruby class for it. Currently I’m setting up a JSON file parser, and this will make my job so much easier.

    Two thumbs up!

  • http://lecklider.com Evan

    Off topic question about your shell: how’d you get ZSH outputting such nice colors? I use ZSH too but couldn’t get anything quite as good looking as what you’ve got (it almost looks like MacVim or something).

    Thanks!

  • http://laminbarrow.com Lamin Barrow

    Ah. Ruby makes every things seem to easy. Keep the newbies suff coming. (y)

  • http://sanandnarayan.com Anand

    Starting building a small web framework on ruby , based on how RoR works , like MVC , ORM , controllers generation . This will help us to understand how ruby connects with the web and also the principle behind these frameworks . That should be a fantastic route ahead :-) , cheers lovely work

  • Dimitar

    Please continue in core ruby. There are quite a bit tutorials on Ruby on Rails, and quite a few on plain Ruby. If you ask me i would like to see this tutorial get some gui ( Qt maybe ?:D ).

    puts “Greetings and thanks for the great tutorials”

  • http://www.bmoja.com Kiash

    Nice~!!

  • http://multi-core-dump.blogspot.com/ coredump

    Big thanks for this great series :) I totally enjoyed all articles :)
    I would definitely like to see more towards web, looking forward to it !

  • Ross

    Andrew – I’m loving the series…Keep them coming! I would love for you to build a sample practical ruby application before we move to the web. Just my two cents.

  • http://rubylearning.com/blog/ Satish Talim

    Andrew, thank you for mentioning RubyLearning’s blog.

  • http://www.rizecorp.com martinkaden

    Thanks for provide this tutorial with us, i Lilly like this posting.

  • http://www.newtnetnews.com/ Christoph Rumpel

    Hi,
    good tutorial, but the echo is totally annoying.
    Greets

  • Aryans Vinay

    Great Series Going ON!! Thanx @Andrew

  • David

    I’m really enjoying this series. So far what I like about Ruby is the blocks and that I can define/redefine the operators. Thanks again for making these available.

  • fnaadb

    excellent article, really enjoyed it

  • anon

    It’s File.absolute, not File.absotule (in the code sample.) Might want to fix that.