380 likes | 533 Vues
CSE 20232 Lecture 7 – Loops, Files & More. Loop Termination By Count Sentinel Value End of Input File Operations with streams ifstream, ofstream, open(), close(), >>, << Linux Piping and I/O redirection |, <, >, >>. Later this week …. Command Line Arguments “C” style I/O
E N D
CSE 20232Lecture 7 – Loops, Files & More • Loop Termination • By Count • Sentinel Value • End of Input • File Operations with streams • ifstream, ofstream, open(), close(), >>, << • Linux Piping and I/O redirection • |, <, >, >>
Later this week … • Command Line Arguments • “C” style I/O • printf(…), scanf(…), fprinf(…), fscanf(…)
Reading (same as last time) • All previously assigned PLUS … • Control Structures • Sections 5.1-5.10 • I/O Streams • Sections 15.3-15.5, 15.7-15.8 • File Streams & Sequential files • Sections 17.3-17.5
Simple avg Program • For today we will use variations of a simple grade averaging program • avgN.cpp - Loop termination by count • User provided # of values and then the values themselves • avgS.cpp – Loop termination by sentinel value • User provides numbers followed by a sentinel value • The sentinel is outside the normal data value range • avgE.cpp – Loop termination by end of input detection • User provides numbers followed by <ctrl-d>
Program “avgN.cpp” // file: avgN.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates by count) #include <iostream> using namespace std; int main () { int n, value, sum(0); // initialize sum to 0 cout << “How many values will be entered? “; cin >> n; for (int i=0; i<n; i++) { cout << “Enter value [“ << i << “] “; cin >> value; sum = sum + value; } if (n == 0) cout << “No values were averaged!” << endl; else cout << “Average of the “ << n << “ values is “ << (sum / n) << endl; return 0; }
Using avgN(user inputs underlined) How many values will be entered? 5 Enter value [0] 10 Enter value [1] 20 Enter value [2] 30 Enter value [3] 40 Enter value [4] 50 Average of the 5 values is 30
Program “avgS.cpp” // file: avgS.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates by sentinel -99) #include <iostream> using namespace std; int main () { int n(0), value, sum(0); // initialize n and sum to 0 cout << “Enter non negative values to be averaged.“ << endl; cout << “Enter value (-99 when done): “; cin >> value; while (value != -99) { n = n + 1; sum = sum + value; cout << “Enter value (-99 when done): “; cin >> value; } if (n == 0) cout << “No values were averaged!” << endl; else cout << “Average of the “ << n << “ values is “ << (sum / n) << endl; return 0; }
Using avgS(user inputs underlined) Enter non negative values to be averaged. Enter value (-99 when done): 10 Enter value (-99 when done): 20 Enter value (-99 when done): 30 Enter value (-99 when done): 40 Enter value (-99 when done): 50 Enter value (-99 when done): -99 Average of the 5 values is 30
Program “avgE.cpp” // file: avgE.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates on end of input) #include <iostream> using namespace std; int main () { int n(0), value, sum(0); // initialize n and sum to 0 cout << “Enter non negative values to be averaged.“ << endl; cout << “Enter value (<ctl-d> when done): “; while (cin >> value) { n = n + 1; sum = sum + value; cout << “Enter value (<ctl-d> when done): “; } cout << endl; // since <ctl-d> does not move us down the screen if (n == 0) cout << “No values were averaged!” << endl; else cout << “Average of the “ << n << “ values is “ << (sum / n) << endl; return 0; }
Using avgE(user inputs underlined) Enter non negative values to be averaged. Enter value (<ctl-d> when done):10 Enter value (<ctl-d> when done):20 Enter value (<ctl-d> when done):30 Enter value (<ctl-d> when done):40 Enter value (<ctl-d> when done):50 Enter value (<ctl-d> when done): Average of the 5 values is 30 NOTE: <ctl-d> was entered at last prompt.
Why use files? • Files save data and results for future use • Files continue to exist when computer is OFF • Files may be shared • User is not required to reenter data every time program is used • Files may be used to accumulate more data over time • Files may be used to take output from one program into another as input
Files and File Streams • The two C++ file stream types used to access and manipulate sequential files are … • ifstream – the input file stream • ofstream – the output file stream • They are defined in the header <fstream>, so • #include <fstream>
Declaring ifstream Objects and Opening Input Files • Declaring an ifstream and opening a file for input in one statement • ifstream infile(“valuesN.txt”); • Declaring an ifstream and opening a file in a later statement • ifstream infile; • infile.open(“valuesN.txt”);
Declaring ifstream Objects and Opening Input Files • Declaring an ifstream, asking the user for a file name, and opening the requested file • string filename; • ifstream infile; • cout << “Enter filename: “; • cin >> filename; • infile.open(filename.c_str()); • note: c_str() function is used above to convert filename string object to the required C-style character array
Reading from an Input File • Once the file is open (and associated with the input file stream) … • Use the stream just like you would use cin, except you will be getting input from the file • infile >> value; // get a value • ch = Infile.get(); // get a character • getline(infile,str); // get a line
Opening an Output File • Declaring an ofstream and opening a file for output in one statement • ofstream outfile(“results.txt”); • Declaring an ofstream and opening a file in a later statement • ofstream outfile; • outfile.open(“results.txt”);
Opening an Output File • Declaring an ofstream, asking the user for a file name, and opening the requested file • string filename; • ofstream outfile; • cout << “Enter filename: “; • cin >> filename; • outfile.open(filename.c_str()); • note: c_str() function is used above to convert filename string object to the required C-style character array
Writing to an Output File • Once the file is open (and associated with the output file stream) … • Use the stream just like you would use cout, except you will be sending output to the file • outfile << value; // send a value • outfile.put(ch); // send a character • outfile << “This & that”; // send a line
Simple avg Program (file input) • Now we will examine variations of a simple grade averaging program that uses a file for input • avgNf.cpp - Loop termination by count • User provided # of values and then the values themselves • avgSf.cpp – Loop termination by sentinel value • User provides numbers followed by a sentinel value • The sentinel is outside the normal data value range • avgEf.cpp – Loop termination by end of input detection • User provides numbers followed by <ctrl-d>
Changes to average program • Obviously … • Files do not need to be prompted for input • And … • Somehow the program needs to find out the name of the file containing the data vales • Embed the name in the program, • Always assume the same file holds the data • Ask the user for the file name • Allow use of multiple data value files • We will do this for now …
Example Data Files valuesN.txtvaluesS.txtvaluesE.txtvaluesERR.txt 10 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5 6 6 xxx 6 7 7 6 7 8 8 7 8 9 9 8 9 10 10 9 10 -99 10 _ (counted) (sentinel) (end of file)(error)
Program “avgNf.cpp” // file: avgNf.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates by count) #include <iostream> #include <fstream> #include <string> using namespace std; int main () { ifstream infile; // here is our input file stream string filename; // and here is the name of the file on disk int n(0), value, sum(0); // initialize sum to 0 cout << “What is the name of the data file? “; cin >> filename; infile.open(filename.c_str()); // attempt to open the file if (infile.fail()) // we may or may not succeed { cout << “Could not open file:” << filename << endl; return 1; }
Program “avgNf.cpp” // the file was successfully opened, so lets read from it infile >> n; // read the number of data values to follow for (int i=0; i<n; i++) // for each of the n values { infile >> value; // read the next data value cout << “Value [“ << i << “] is “ << value << endl; sum = sum + value; // add it to the sum } infile.close(); // close the file, we are done if (n == 0) cout << “No values were averaged!” << endl; else cout << “Average of the “ << n << “ values is “ << (sum / n) << endl; return 0; }
Using avgNf(user inputs underlined) What is the name of the data file? valuesN.txt Value [0] is 1 Value [1] is 2 Value [2] is 3 Value [3] is 4 Value [4] is 5 Value [5] is 6 Value [6] is 7 Value [7] is 8 Value [8] is 9 Value [9] is 10 Average of the 10 values is 5
Program “avgSf.cpp” // file: avgSf.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates by sentinel -99) #include <iostream> #include <fstream> #include <string> using namespace std; int main () { ifstream infile; // here is our input file stream string filename; // and here is the name of the file on disk int n(0), value, sum(0); // initialize n and sum to 0 cout << “What is the name of the data file? “; cin >> filename; infile.open(filename.c_str()); // attempt to open the file if (infile.fail()) // we may or may not succeed { cout << “Could not open file:” << filename << endl; return 1; }
Program “avgSf.cpp” // the file was successfully opened, so lets read from it infile >> value; // get first value while (value != -99) // for every value until sentinel { cout << “Value [“ << n << “] is “ << value << endl; n = n + 1; // count it sum = sum + value; // add value to sum infile >> value; // get next value } infile.close(); // close the file, we are done if (n == 0) cout << “No values were averaged!” << endl; else cout << “Average of the “ << n << “ values is “ << (sum / n) << endl; return 0; }
Using avgSf(user inputs underlined) What is the name of the data file? valuesS.txt Value [0] is 1 Value [1] is 2 Value [2] is 3 Value [3] is 4 Value [4] is 5 Value [5] is 6 Value [6] is 7 Value [7] is 8 Value [8] is 9 Value [9] is 10 Average of the 10 values is 5
Program “avgEf.cpp” // file: avgEf.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates on end of input) #include <iostream> #include <fstream> #include <string> using namespace std; int main () { ifstream infile; // here is our input file stream string filename; // and here is the name of the file on disk int n(0), value, sum(0); // initialize n and sum to 0 cout << “What is the name of the data file? “; cin >> filename; infile.open(filename.c_str()); // attempt to open the file if (infile.fail()) // we may or may not succeed { cout << “Could not open file:” << filename << endl; return 1; }
Program “avgEf.cpp” // the file was successfully opened, so lets read from it while (infile >> value) // get next value { cout << “Value [“ << n << “] is “ << value << endl; n = n + 1; // count it sum = sum + value; // add value to sum } infile.close(); // close the file, we are done if (n == 0) cout << “No values were averaged!” << endl; else cout << “Average of the “ << n << “ values is “ << (sum / n) << endl; return 0; }
Using avgEf(user inputs underlined) What is the name of the data file? valuesE.txt Value [0] is 1 Value [1] is 2 Value [2] is 3 Value [3] is 4 Value [4] is 5 Value [5] is 6 Value [6] is 7 Value [7] is 8 Value [8] is 9 Value [9] is 10 Average of the 10 values is 5
Warning about Stream Errors • If an error occurs while using a stream … • The stream is placed in an error state • All subsequent uses of the stream will be skipped as the program continues to run • To fix this and continue … • If a stream fails, always execute its clear() function to clear the error state, before using it again • Examples: • Failing to open a file, you must clear the ifstream before using it to try and open another • Failing to read some data, you must clear the ifstream and skip over the offending bad data before attempting to continue reading more data
Errors in streams • The previous programs will stop accessing file “valuesERR.txt” when the “xxx” line is encountered • Run avgEf on “valuesERR.txt” to see • The next program (avgERRf.cpp) clears the stream, skips over the bad data, and continues
Using avgEf with “valuesERR.txt”(user inputs underlined) What is the name of the data file? valuesERR.txt Value [0] is 1 Value [1] is 2 Value [2] is 3 Value [3] is 4 Value [4] is 5 Average of the 5 values is 3 Note: All data following “xxx” in the 6th line of the file was skipped due to the error state of stream
Program “avgERRf.cpp” // file: avgERRf.cpp // JHS (2006) – CSE 20232 // Average n non negative integer values (loop terminates on end of input) // This copes with error in stream, that can be skipped (bad number) #include <iostream> #include <fstream> #include <string> using namespace std; int main () { ifstream infile; // here is our input file stream string filename; // and here is the name of the file on disk int n(0), value, sum(0); // initialize n and sum to 0 cout << "What is the name of the data file? "; cin >> filename; infile.open(filename.c_str()); // attempt to open the file if (infile.fail()) // we may or may not succeed { cout << "Could not open file:" << filename << endl; return 1; }
Program “avgERRf.cpp” // the file was successfully opened, so lets read from it infile >> value; // get first value while (!infile.eof()) // get next value and ... { if (infile.fail()) { string junk; infile.clear(); // must have been a bad number format, skip it infile >> junk; // skip over junk (bad number) } else { cout << "Value [" << n << "] is " << value << endl; n = n + 1; // count it sum = sum + value; // add value to the sum } infile >> value; // get another value }
Program “avgERRf.cpp” // finally done with reading data from the file infile.close(); // close the file, we are done if (n == 0) cout << "No values were averaged!" << endl; else cout << "Average of the " << n << " values is " << (sum / n) << endl; return 0; }
Using avgERRf & “valuesERR.txt”(user inputs underlined) What is the name of the data file? valuesERR.txt Value [0] is 1 Value [1] is 2 Value [2] is 3 Value [3] is 4 Value [4] is 5 Value [5] is 6 Value [6] is 7 Value [7] is 8 Value [8] is 9 Value [9] is 10 Average of the 10 values is 5 Note: The “xxx” on the 6th line of the file was skipped and the rest of the data was processed.
Summary • Three ways to terminate loops • By count • By sentinel • By end of input • Files are • Accessed using ifstream and ofstream objects • Opened at time of declaration or with open() • Values are extracted from the stream just like they are from cin • Stream access following an error will be skipped unless stream is cleared