EECS168 09:Lab8

From ITTC
Jump to: navigation, search
Navigation
Home
Information

Syllabus
Schedule
Lecture Notes
Exam Reviews

Classwork

Labs
Homework
Submitting Work


Objectives

  • Read from files and write to files.
  • Read an arbitrary amount of information from a file.
  • Use get and put.

Writing To a File

First, you will write to a file. Copy the following code to a file named write.cpp:

#include <iostream>
#include <string>
#include <fstream>          // You need this to work with files
using namespace std;

int main()
{
    ofstream outfile;       // create a file variable
    string filename;      // a variable to hold the name of a file
    
    cout << "Enter the name of the file to write to: ";
    cin >> filename;
    outfile.open(filename.c_str());
    
    
    outfile << "This is a string that will be written to the file!" << endl;
    outfile << 3 << endl;
    outfile << 1.0 / 5.0 << endl;
    
    outfile.close();
    return 0;
}

There are a few new things in this code:

#include <fstream>
#include statements copy code into our program so that we can use it. We've been including iostream, which lets us use cout and endl. In order to use ofstream, we need to include fstream.
ofstream outfile;
Just like "int x" would create an integer variable named x, "ofstream outfile" creates an ofstream -- an output file stream -- named outfile.
string filename;
This is a string variable, that we will use to hold the name of the file.
outfile.open(filename.c_str());
open does just what it sounds like: it opens the file.
outfile.close();
When you are done with the file, you should close it.

Reading From a File

Copy the following code to file named input.cpp:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream my_file; 
    
    cout << "Opening file \"input.txt\"..." << endl;
    
    my_file.open("input.txt");
    
    // this comment is a place-holder
    
    char in_char;
    string in_string1, in_string2;
    int n1, n2, n3;
    
    my_file >> in_char;
    my_file >> in_string1;
    my_file >> in_string2;
    my_file >> n1 >> n2 >> n3;
    
    cout << "in_char: " << in_char << endl;
    cout << "in_string1: " << in_string1 << endl;
    cout << "in_string2: " << in_string2 << endl;
    cout << "average of n1, n2, and n3: " << (n1 + n2 + n3) / 3.0 << endl;
    
    my_file.close();
    return 0;
}

Notice that this code isn't asking you for a file name; instead, it's uses a hard-coded file name, input.txt. This program always tries to open a file with that name. Try running this program right now, without any file named input.txt in the directory. It runs without complaint! Since it couldn't read anything, the output values are garbage. We want to avoid this problem, so we need to check if the program successfully opened the file.

Add this line to the top of input.cpp:

#include <cstdlib>

Copy this code into input.cpp, right after the comment that says "this comment is a place-holder":

if (my_file.fail())
{
    cout << "Failed to open file." << endl;
    exit(1);
}

Now, compile and run the program again. Now, if there is no input.txt file, the program will quit with an error message. Most programs you write that use files should include this kind of error checking. Your textbook describes it in more detail on page 307.

Copy the following text into a file named input.txt, save it, and run the program again.

Hello, world!
2
6
10

Note how the stream input works. When you read the first character, it is "consumed," i.e., it is not there for the next read. Also note how the input stream uses whitespace delineation when reading strings.

Reading Arbitrary Amounts of Data

So far, you have only read from files where you knew how exactly how much data you wanted to read. What if you don't know how much data there will be? The following program reads in numbers from a file, then prints the average of those numbers, without knowing how many numbers there will be ahead of time.

#include <cstdlib>
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    string filename;
    cout << "Enter the name of the file to read: ";
    cin >> filename;
    ifstream number_file;
    number_file.open(filename.c_str()); 
    
    if (number_file.fail())
    {
        cout << "Failed to open file." << endl;
        exit(1);
    }
    
    int input;
    int count = 0;
    double total = 0;
    
    while(number_file >> input)
    {
        count++;
        total += input;
    }
    
    number_file.close();
    
    cout << "The average of all numbers was " << total / count << endl;
    
    return 0;
}

The "while(number_file >> input)" line is a little tricky, because it's doing two things:

  • It's attempting to read a value into input.
  • It returns a bool value based on whether or not it successfully read a value.

Reading Characters

#include <cstdlib>
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    string filename;
    cout << "Enter the name of the file to read: ";
    cin >> filename;
    ifstream infile;
    infile.open(filename.c_str()); 
    
    if (infile.fail())
    {
        cout << "Failed to open file." << endl;
        exit(1);
    }
    
    char input;
    
    while(infile >> input)
    {
        cout << input;
    }
    
    infile.close();
    
    return 0;
}

Notice that this will ignore all whitespace, such as spaces and newlines. That's because the stream operators are whitespace delineated. What if you want to get every character, even whitespace characters? In the code you could replace the line that reads

while(infile >> input)

with the following line:

while(infile.get(input))

Now, the whitespace is being preserved. put and get are member functions of C++ streams and are described further on page 333 of your textbook.

Construct Your Own Programs From Scratch

Copy the following text into a file called numbers.dat:

11 21 32 45 52 62 71 81 92 10 
95 87 71 66 54 55 34 22 11 17
85 71 61 52 46 37 28 18 91 13

Now write a program findNumber.cpp that reads the file numbers.dat and asks the user to enter a number. The program will output whether the number exists in the file or not. Also make your program output the place of the number in the file. For example I want to know if number 71 exists in the file. The output from the program would be as follows.

The number 71 is found in the file, in the place 7
The number 71 is found in the file, in the place 13
The number 71 is found in the file, in the place 22

You will now create a new program findEven.cpp that will read the same file numbers.dat and write to a file which should be called results.dat. Your program should read each integer and determine if it is even or odd. If it is even you should write to the file a 1 if it is odd you should write to the file a 0. So, for the first line of input the first line of output should look like

0 0 1 0 1 1 0 0 1 1

Make your program count the number of even and number of odd numbers and display both totals to the user before exit.

Lab Submission

  • findNumber.cpp
  • findEven.cpp
  • results.dat

The submission procedure is the same as was described in previous labs, except that:

  • Your tarball and the directory inside it should be named like Smith-1234567-Lab-08
  • The email subject should be "[EECS 168] Lab 08" (without the quotes).

Remember to include your full name, student number, and disk usage in the email.