Chapter 13. Files and IO

image with no caption

Ruby provides classes dedicated to handling input and output (IO). Chief among these is a class called, unsurprisingly, IO. The IO class lets you open and close IO streams (sequences of bytes) and read and write data to and from them.

For example, assuming you have a file called textfile.txt, containing some lines of text, this is how you might open the file and display each line on the screen:

io_test.rb

IO.foreach("testfile.txt") {|line| print( line ) }

Here foreach is a class method of IO, so you don’t need to create a new IO object to use it; instead, you just specify the filename as an argument. The foreach method takes a block into which each line that is read from the file is passed as an argument. You don’t have to open the file for reading and close it when you’ve finished (as you might expect from your experience with other languages) because Ruby’s IO.foreach method does this for you.

IO has a number of other useful methods. For example, you could use the readlines method to read the file contents into an array for further processing. Here is a simple example that once again prints the lines to screen:

lines = IO.readlines("testfile.txt")
lines.each{|line| print( line )}

The File class is a subclass of IO, and the previous examples could be rewritten using the File class:

file_test.rb

File.foreach("testfile.txt") {|line| print( line ) }

lines = File.readlines("testfile.txt")
lines.each{|line| print( line )}

Opening and Closing Files

Although some standard methods open and close files automatically, often when processing the contents of a file, you will need to open and close the file explicitly. You can open a file using either the new or open method. You must pass two arguments to one of those methods—the filename and the file “mode”—and it returns a new File object. The File modes may be either integers that are defined by operating system-specific constants or strings. The mode generally indicates whether the file is be opened for reading ("r"), writing ("w"), or reading and writing ("rw"). Table 13-1 shows the list of available string modes.

Table 13-1. File Mode Strings

Mode

Meaning

"r"

Read-only, starts at beginning of file (default mode)

"r+"

Read-write, starts at beginning of file

"w"

Write-only, truncates existing file to zero length or creates a new file for writing

"w+"

Read-write, truncates existing file to zero length or creates a new file for reading and writing

"a"

Write-only, starts at end of file if file exists; otherwise, creates a new file for writing

"a+"

Read-write, starts at end of file if file exists; otherwise, creates a new file for reading and writing

"b"

(DOS/Windows only) Binary file mode (may appear with any of the key letters listed earlier)

Let’s look at an actual example of opening, processing, and closing files. In open_close.rb, I first open a file, myfile.txt, for writing ("w"). When a file is opened for writing, a new file will be created if it doesn’t already exist. I use puts() to write six strings to the file, one string on each of six lines. Finally, I close the file:

f = File.new("myfile.txt", "w")
f.puts( "I", "wandered", "lonely", "as", "a", "cloud" )
f.close

Closing a file not only releases the file handle (the pointer to the file data) but also “flushes” any data from memory to ensure that it is all saved into the file on disk.

Having written text into a file, let’s see how to open that file and read the data back in. This time I’ll read in the data one character at a time up to the end of the file (eof). As I do so, I’ll keep a count of the characters that have been read. I’ll also keep a count of the lines, which will be incremented whenever I read in a linefeed character (given by ASCII code 10). For the sake of clarity, I’ll add a string to the end of each line that’s been read, displaying its line number. I’ll display the characters plus my line-end strings on the screen, and when everything has been read from the file, I’ll close it and display the statistics that I’ve calculated. Here is the complete code:

open_close.rb

f = File.new("myfile.txt", "w")
f.puts( "I", "wandered", "lonely", "as", "a", "cloud" )
f.close                          # Try commenting this out!

charcount = 0
linecount = 0
f = File.new("myfile.txt", "r")
while !( f.eof ) do              # while not at end of file...
    c = f.getc()                 # get a single character
    if ( c.ord == 10 ) then      # test ASCII code (Ruby 1.9)
        linecount += 1
        puts( " <End Of Line #{linecount}>" )
    else
        putc( c )                # put the char to screen
        charcount += 1
    end
end
if f.eof then
    puts( "<End Of File>" )
end
f.close
puts("This file contains #{linecount} lines and #{charcount} characters." )

Note

This code is written for Ruby 1.9 and won’t run in Ruby 1.8. See the following section for more details.

When manipulating files in this way, it is the programmer’s responsibility to ensure that the file is closed after data is written to or read from it. Failing to close a file may result in unpredictable side effects. For example, try commenting out the first f.close (on the third line in the previous code) to see for yourself! You’ll find that when the program subsequently tries to read back the contents of the file, no data is found, and a count of zero lines and characters is returned!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.246.148