I l@ve RuBoard |
![]() ![]() |
1.7 Writing and Reading FilesIf a user should happen to run our program a second time, it would be nice to allow her score to reflect both sessions. To do this, we must (1) write the user's name and session data to a file at the end of the session and (2) read the user's session data back into the program at the start of the next session. Let's see how we might do that. To read and write to a file, we must include the fstream header file: #include <fstream> To open a file for output, we define an ofstream (an output file stream) class object, passing it the name of the file to open: // seq_data.txt is opened in output mode ofstream outfile( "seq_data.txt" ); What happens when we declare outfile? If it doesn't exist, the file is created and opened for output. If it does exist, it is opened for output and any existing data in the file is discarded. If we wish to add to rather than replace the data within an existing file, we must open the file in append mode. We do this by providing an ios_base::app second value to the ofstream object. (At this point in this book, it is better that you just use this and not inquire too deeply as to what the heck it actually is!) // seq_data.txt is opened in append mode // new data is added at the end of the file ofstream outfile( "seq_data.txt", ios_base::app ); A file may fail to open. Before we write to it, we must confirm that it has been opened successfully. The simplest way to check that is to test the truth value of the class object: // if outfile evaluates as false, // the file could not be opened if ( ! outfile ) If the file could not be opened, the ofstream class object evaluates to false. In this example, we alert the user by writing a message to cerr. cerr represents standard error. cerr, like cout, directs its output to the user's terminal. The difference is that cerr's output is not buffered; it displays on the user's terminal immediately. if ( ! outfile ) // open failed for some reason ... cerr << "Oops! Unable to save session data!\n"; else // ok: outfile is open, let's write the data outfile << usr_name << ' ' << num_tries << ' ' << num_right << endl; If the file is opened successfully, we direct output to it in the same way as we do for the ostream class objects cout and cerr. In this example, we write three values to outfile, the second two separated by a space. endl is a predefined manipulator provided by the iostream library. A manipulator performs some operation on the iostream rather than write or read data. endl inserts a newline character and then flushes the output buffer. Other predefined manipulators include hex, which displays an integer value in hexidecimal notation; oct, which displays an integer value in octal notation; and setprecision(n), which sets the display of floating point precision to n. (For a full list of the predefined iostream manipulators, refer to Section 20.9 of [LIPPMAN98].) To open a file for input, we define an ifstream class object (an input file stream), passing it the name of a file. If the file cannot be opened, the ifstream class object tests as false. Otherwise, the file is positioned at the beginning of the data stored in the file. // infile opened in output mode ifstream infile( "seq_data.txt" ); int num_tries = 0; int num_cor = 0; if ( ! infile ) { // open failed for some reason ... // we'll presume it is a new user ... } else { // ok: read each line of the input file // see if user has played before ... // format of each line: // name num_tries num_correct // nt: number of tries // nc: number of correct guesses string name; int nt; int nc; while ( infile >> name ) { infile >> nt >> nc; if ( name == usr_name ) { // match! cout << "Welcome back, " << usr_name << "\nYour current score is " << nc << " out of " << nt << "\nGood Luck!\n"; num_tries = nt; num_cor = nc; } } } Each iteration of the while loop reads the next line of the file until the end-of-file is reached. When we write infile >> name the return value of the input statement is the class object from which we are reading ? infile in this case. When the end-of-file is reached, the truth condition of the class object evaluates to false. This is why the conditional expression of the while loop terminates when end-of-file is reached: while ( infile >> name ) Each line of the file contains a string followed by two integers, of the form anna 24 19 danny 16 12 ... The line infile >> nt >> nc; reads in turn the number of user guesses into nt and the number of correct guesses into nc. If we wish to both read from and write to the same file, we define an fstream class object. To open it in append mode, we must provide a second value of the form ios_base::in|ios_base::app: [2]
fstream iofile( "seq_data.txt", ios_base::in|ios_base::app ); if ( ! iofile ) // open failed for some reason ... darn! else { // reposition to front of file to begin reading iofile.seekg( 0 ); // ok: everything else is the same ... } When we open a file in append mode, the current position of the file is at the end. If we try to read the file without repositioning it, we simply encounter the end-of-file. The seekg() operation repositions iofile to the beginning of the file. Because it is opened in append mode, any write operation adds the data to the end of the file. The iostream library is rich in functionality, many of the details of which I haven't the space to cover here. For a detailed discussion of the iostream library, see Chapter 20 of [LIPPMAN98] or Chapter 21 of [STROUSTRUP97]. Exercise 1.5Write a program to ask the user his or her name. Read the response. Confirm that the input is at least two characters in length. If the name seems valid, respond to the user. Provide two implementations: one using a C-style character string, and the other using a string class object. Exercise 1.6Write a program to read in a sequence of integers from standard input. Place the values, in turn, in a built-in array and a vector. Iterate over the containers to sum the values. Display the sum and average of the entered values to standard output. Exercise 1.7Using your favorite editor, type two or more lines of text into a file. Write a program to open the file, reading each word into a vector<string> object. Iterate over the vector, displaying it to cout. That done, sort the words using the sort() generic algorithm, #include <algorithm> sort( container.begin(), container.end() ); Then print the sorted words to an output file. Exercise 1.8The switch statement of Section 1.4 displays a different consolation message based on the number of wrong guesses. Replace this with an array of four string messages that can be indexed based on the number of wrong guesses. |
I l@ve RuBoard |
![]() ![]() |