File Input/Output
11.1 Introduction
Until this point, all of our programs have taken a data set of values from user input. Any given program took in one data set, which consisted of one or more related values from the user, and then performed a computation based on that data set. Imagine a program that has many data sets, each consisting of multiple values. Entering all the data sets by hand could be somewhat time-consuming. Also, some data sets may come from external sources and not directly from the user.
The techniques presented in this chapter will allow you to manipulate files and utilize their data within your software. File input/output (I/O) allows software to perform computations on sets of data until a desired end result is achieved.
11.2 File Access: Reading and Writing
To access files, the built-in Ruby File class is used. This class contains multiple
methods. We use the following: open,
close, gets, and puts. The method File.open instantiates a new object that enables
Ruby to read from or write to an existing or new file. The object returned
by File.open can then be used by Ruby
to access the file. The following code shows how to open a file:
myfile=File.open(file_name,access_mode)
The myfile variable is a File object that can now be used to interact
with the file’s contents, depending on what access mode is used. Note that
file name and access mode are strings. The variable file_name is a representation of a path to a
file, such as /home/ruby/file.txt. The myfile variable in our program is local to only
our program. Two of the most basic access modes and what they do are shown
in Table 11-1.
| Mode | Description |
|---|---|
| Read access only. Points to start of the file. This is the default, but it is good programming style to specify it anyway. |
| Write access only. Points to the beginning of the file that will overwrite the file’s content if it already exists. |
Gem of Wisdom
Files provide access to data resident in the computer system’s long-term memory. Storage in long-term memory, such as disks, provides data resiliency, namely, permanence. That is, disks work even without power, so they store things far longer than the internal random access memory, which works only if the power is on.
To read a line of characters from a file, call the gets method on the myfile object. When the gets method is called, it reads characters until
it reaches a newline character (\n),
and then it returns what it read. The File object keeps track of what has been read
in, so each successive call to gets
will always return the next line, until it reaches the end of the file and
returns nil. nil has the logical truth value of false. Every other value returned by gets has the logical value of true. Consider the code provided in Example 11-1, which reads in a file foo.txt and then prints it out.
Sample code for file reading
1myfile=File.open("foo.txt","r")2whole_file=""34while(input_line=myfile.gets)5whole_file+=input_line6end78puts"Contents of input file:"9putswhole_file10myfile.close()
Line 1 opens
foo.txtfor read access.Line 2 instantiates an empty string variable,
whole_file, which will be used to store the file to display.Lines 4–6 contain a loop that reads the file into
input_line, one line at a time, and appends each line intowhole_file.Line 9 prints out the file.
Sequentially writing to a file is similar to sequentially reading
from a file. Instead of opening the file in read mode, the file needs to
be opened with w for writing access. To
write text to a file, use the local variable myfile to call the puts method:
myfile.puts("text goes here!")
The code shown in Example 11-2 opens a file for write access, accepts user input, and writes that input to the file. It will then close the file, reopen it, and print the contents to verify correctness.
File read/write example
1file_a=File.open("bar.txt","w")23puts"Please enter a line of text"4line=gets()5file_a.puts(line)6file_a.close()78file_b=File.open("bar.txt","r")9puts"Contents of file:"10putsfile_b.gets()11file_b.close()
Line 1 opens
bar.txtas file objectfile_awith write access.Lines 3–4 take text input from the user.
Line 5 writes the user input into
"bar.txt".Line 6 closes the
Fileobjectfile_a(this saves the text inside it by closing the file and preventing further access to it).Line 8 instantiates a new
Fileobjectfile_b. This object will be used for the purpose of reading the content ofbar.txt. Note the file access moder.Line 10 outputs the contents of the newly created file to the console, illustrating that the code in Example 11-2 behaves in the desired fashion.
11.2.1 File Reader Class
We will now define two classes that encapsulate reading in a file and writing out a file. Then we will use the two classes to create a file copy program that will read text from a file and then copy the text into a new file.
The class presented in Example 11-3 encapsulates reading and displaying a file.
FileReader class
1classFileReader23definitialize(file_name)4@file=File.open(file_name,"r")5end67defread_file8whole_file=""9while(input_line=@file.gets)10whole_file+=input_line11end1213returnwhole_file14end1516defdisplay17puts"Contents of input file:"18putsread_file19end2021defclose22@file.close()23end24end
Lines 3–5 define the constructor. The variable
@filereferences theFileobject that has been opened.Line 4 opens the file for the purpose of reading the contents. The
rindicates that this file is to be open for reading.Lines 7–14 define the
read filemethod. This method incorporates a basic loop that goes through a given file usinggetsfor the purpose of reading one line at a time.Line 10 appends (adds to the end of the string) to
whole_filethe contents of the currently read line of the file.Line 13 returns the contents of the file that is now stored in
whole_file.Lines 16–19 define a display method that outputs the contents of the file.
Lines 21–23 define a close method that closes the opened file,
@file.
11.2.2 FileWriter Class
The class in Example 11-4 encapsulates writing to and closing a file.
FileWriter class
1classFileWriter23definitialize(file_name)4@file=File.open(file_name,"w")5end67defwrite_line(output_line)8@file.puts(output_line)9end1011defclose12@file.close()13end14end
Lines 3–5 define the constructor.
Line 4 opens the file
file_nameusingwfor write access mode.Lines 7–9 define the
write_linemethod, which outputs a single line,output_line, to a file associated with theFileWriterobject.Line 8 makes use of the
putsmethod to output the contents of a givenoutput_lineto the file referenced by@file.Lines 11–13 close the file. This ensures that all the data that have been written to the file are actually written to it. That is, data that are temporarily buffered in intermediate storage are actually written to secondary (permanent) storage. Buffering is commonly used to reduce output writing delays.
The above use of buffers may seem obscure for a reader who is not
familiar with the actual mechanisms employed in writing a file. In
reality, the puts method does not actually write to a
file; it actually fills a holding area commonly referred to as a
buffer.
11.2.3 File Reader/Writer Example
The code in Example 11-5
will read in a file and write the contents out to a new file. This code
assumes you have written out the class definitions for FileReader and FileWriter
given in the preceding section as files named file_reader.rb and file_writer.rb.
FileReader/FileWriter example
1require_relative"file_reader.rb"2require_relative"file_writer.rb"34fr=FileReader.new("input.txt")5fw=FileWriter.new("output.txt")67input=fr.read_file()8fw.write_line(input)910fw.close()11fr.close()
Lines 1 and 2 import the class definitions of
FileReaderandFileWriter.Lines 4 and 5 create instances of our two classes, the first for input, the second for output.
Line 7 reads the file into a string called
input.Line 8 writes the string
inputout to the file held by the instance ofFileWriter.Lines 10 and 11 close both of the open files.
To verify that the code presented in Example 11-5 works correctly, use
the input text file with the content shown in Example 11-6. After running Example 11-5’s code with the input
from Example 11-6, ensure that output.txt is the same as input.txt.
Sample input file
Helloworld!Amightyfinedayforrubyprogramming!ComputerScienceisthebest!
11.3 Summary
We described basic file input and output operations.
11.3.1 Key Concepts
Text files in Ruby are contiguous streams of data in the form of characters.
Data can be entered into a program using file access; this is done through file input/output or I/O.
To read from or write to a file, one must access the file through Ruby’s
Fileclass.
11.3.2 Key Definitions
File access: Opening a file for reading or writing.
Input: Reading information from a stored file.
Output: Writing information to a file for storage.
11.4 Exercises
The game of Go is often played online. Many users save their game data for later analysis. The game is played by two players who take turns placing stones (one player using black stones and the other using white stones) on the intersections of a 19 × 19 board. Create a program to enter each move of a game and save that information to a file.
Write a program that quizzes the user on her or his vocabulary. Make the program read a set of words and definitions from a file; display definitions one at a time, in random order; and prompt for the appropriate word.
Write a program that will keep track of the mileage for oil changes for your car.
Write a program that reads the content of a file and outputs it to the screen.
Write a program that takes input from the user and saves it to a file.
Write a program that creates and stores a simple address book.
