Stream I/O The C++ language itself does not include any input or output facilities. Hence we must use the preprocessor command # include<iostream> in every program that uses input or output. The advantage of handling input and output using libraries is that it is easier to make the language “platform independent” meaning programs written on a PC are likely to work on a Mac or a Sun Workstation. The iostream classes view the flow of data between a program and a device as a stream or a sequence of bytes. If your program is the source of the data stream, then the destination may be the screen or a file. If the stream is reversed, data can come from the keyboard or a file and be poured into your programs variables. Since writing data to a disk or to the screen is time intensive, the iostream classes provide a buffering capability in which data written to the stream, but is not written to the disk immediately. Instead, the stream’s buffer fills and when it is full, the data is written to the disk all at once. The I/O library contains the following class hierarchies for streams. ios_base ios /\ / \ / \ istream ostream / | \ / | \ / | | | \ / / | \ \ / / | \ \ / / | \ \ istring ifstream iostream ofstream ostring stream /\ stream / \ fstream stringstream Stream I/O Library Header Files Use the following list to determine which header files need to be included in your program to accomplish specific input/output tasks. iostream – input to the keyboard and output to the screen. iomanip – formatting input and output. fstream – input and output to files. strstream – input and output to strings in memory, Standard I/O streams When a C++ program that includes the iostream classes starts, the following four objects are created and initialized. Each object has operators and methods that can be used to facilitate the input/output process. cin The purpose of cin is to handle input from the standard input (keyboard). Note that cin overloads the extraction operator (>>). When using the extraction operator we observe that it skips white space characters such as blanks, tabs and new lines to search for the next input. Example: Extraction operator skips over white space. Note all of the following inputs are acceptable to the program below input (1) 2 3.4 5.6 input (2) 2 3.4 5.6 input (3) 2 3.4 5.6 In the first input the numbers are separated by commas, in the second they are separated by tabs and in the third they are separated by new lines. In all cases cin skips over the white space to find the next input. # include<iostream> using namespace std; int main( ) { int n; float x; double y; cin >> n >> x >> y; cout << "n = " << n << " x = " << x << " y = " << y << endl; return 0; } In addition to overloading the extraction operator >>, cin has several additional methods as shown in the table below. In general the extraction operator is easier to use and should be used whenever possible. In some situations when you need to examine every character including white space, these additional methods provide the needed flexibility. cin methods get(character-variable) getline(string-variable, int n , ‘\n’) peek(character-variable) putback(character expression) ignore(n) Extracts the next character from the character stream. Extract characters from the input stream until n-1 characters are read or a new line is encountered. Return the next character in the input stream without extracting it from the stream. Put a character onto the input stream without altering data in the file. Skip over the next n characters. Example: Use the getline method to read in a line up to 79 characters including white space. Note the difference in behavior between the extraction operator and the getline method when the input line contains white space. # include<iostream> # include<string> using namespace std; int main( ) { char c1[80]; char c2[80]; cin.getline(c2,80); cout << c2 << endl; cin >> c1; cout << c1 << endl; return 0; } Example: The following program accepts a phrase, converts lowercase ‘a’ to uppercase and ignores the lowercase ‘b’. # include<iostream> using namespace std; int main( ) { char c; cout << "enter a phrase: "; while (cin.get(c)) { if (c == 'a') cin.putback('A'); else cout << c; while (cin.peek( ) == 'b') cin.ignore(1,'b'); } return 0; } cout The purpose of cout is to handles output to the standard output (screen). Note that cout overloads the insertion operator (<<) and has some additional functions as shown in the following table. The insertion operator should be used whenever possible and the other operators should be used as needed. cout methods put(char) write(string, int n) Insert a character into the character stream. Works the same as the extraction operator except it takes a parameter that tells the function the maximum number of character to write. Example: Using additional methods available to cout. # include<iostream> using namespace std; int main( ) { cout.put('a'); cout << endl; cout.write("Hello world, I'm home.", 10); cout << endl; return 0; } cerr The purpose of cerr is to handle unbuffered output to the standard error device (screen). The output is unbuffered since everything sent to cerr is written to the standard error device immediately without waiting for a buffer to fill. clog The purpose of clog is to handle buffered error messages to the standard error device, the screen. The messages are often redirected to a log file. Manipulate output To format the output in C++ use a combination of escape sequences, output manipulators and flags. Many of these formatting tools require us to include the iomanip header file. Escape sequences \n new line \t tab \\ backslash \a alarm Manipulators flush flushes the output buffer endl flushes the output buffer and inserts a new line oct sets the output base to octal dec sets the output base to decimal hex sets the output base to hexadecimal Parameterized Manipulators setbase(base) setw(width) setfill(char) setprecision(n) setiosflags(flag) resetiosflags(flag) sets the output base (10=decimal, 8=octal, 16 = hex) sets minimum output field width sets the fill character to be used when width is set. sets the precision for floating point numbers. sets one or more of the ios flags shown below resets one or more ios flags Flags (used with setiosflags and resetiosflags manipulators) ios::left left justifies output in specified width. ios::right right justifies output in specified width. ios:decimal decimal output ios::oct octal output ios::hex hexadecimal output ios::showbase adds 0x to hexadecimal numbers and 0 to octal numbers ios::showpoint adds trailing zeros as required by precision ios::uppercase hexadecimal and scientific notation numbers shown in uppercase. ios::showpos show the + sign for positive numbers ios::fixed show floating point numbers in decimal notation Example: Formatting # include<iostream> # include<iomanip> # include<cmath> using namespace std; int main( ) { int n; double d; // // INPUT/OUTPUT MANIPULATORS decimal, octal and hexadecimal n = 23; cout << oct << n << endl; cout << hex << n << endl; cout << dec << n << endl; // setw( ) and setfill( ) field width manipulator cout cout cout cout // << << << << setfill('+'); setw(4) << 6 << endl; setw(4) << 20 << endl; setw(4) << 345 << endl; setprecision( ) for (int places=1; places<=10; places++) cout << setprecision(places) << places << "\t" << sqrt(2.0) << endl; // FORMAT FLAGS // showpoint flag cout << "9.00 prints as: " << 9.00 << endl; cout << "9.70 prints as: " << 9.70 << endl; cout << "9.77 prints as: " << 9.77 << endl; cout << setiosflags(ios::showpoint | ios::showpos); cout << "9.00 prints as: " << 9.00 << endl; cout << "9.70 prints as: " << 9.70 << endl; cout << "9.77 prints as: " << 9.77 << endl; scientific notation cout << setiosflags(ios::scientific) << 23.0 << endl; // character output cout << setiosflags(ios::left); cout << setw(30) << "cat and the hat" << setw(5) << 25 << endl; cout << setw(30) << "fred and company" << setw(5) << 500 << endl; // line up decimal points cout << setw(25) << setprecision(20) << setiosflags(ios::fixed | ios::right) << 23.5 << endl; cout << setw(25) << 455.6677 << endl; return 0; } File I/O streams To store and retrieve data on a file in C++ we use the following four items files file stream objects file stream methods modes File stream objects There are three types of file stream objects used in C++. Each object has operators and methods that can be used to facilitate the file input/output process. ifstream – input file stream object facilitates reading files ofstream – output file stream objects facilitates writing to files. fstream – file stream objects supports both read and write operations on files. If you are going to read from a file create a ifstream object. If you are going to write to a file create an ofstream object. If you are going to both read from and write to a file you must create both an ifstream and an ofstream object. An alternative is to create and fstream object which is capable of both input an output but requires an explicit mode assignment. File stream methods Input file stream objects overload the extraction operator >> and output file stream objects overload the insertion operator <<. In addition each file stream method has access to methods for opening a file, determining if a successful connection has been made, closing a file, getting the next data item from an input stream, placing a new data item on the output stream and detecting when the end of a file has been reached. File stream methods open(external file name) fail( ) close( ) get(character-variable) getline(string-variable, int n , ‘\n’) peek(character-variable) put(character expression) putback (character expression) eof(void) ignore(n) Connects a files external name to the files internal object name. Returns a true value of 1 if the open was successful and a false value 0 if the open failed. Breaks connection between a file’s external name and the file stream object. Extracts the next character from the character stream. Extract characters from the input stream until n-1 characters are read or a new line is encountered. Return the next character in the input stream without extracting it from the stream. Put a character onto the output stream. Put a character onto the input stream without altering data in the file. Returns true (integer value of 1) if a read has been attempted past the end-of-file. Skip over the next n characters. Modes The file modes shown below can be used to modify the behavior of an input or output stream. For example we can set the file mode so that the output is appended to the end of a file rather than writing over the current contents of the file. With an fstream object, the mode is used to determine whether the file is to be used for input or output. File modes ios::in ios::out ios::app open in input mode open in output mode open in append mode ios:ate ios::binary ios::trunc ios::nocreate ios::noreplace go to the end of the file open in binary mode delete file contents if it exists open fails if file does not exist open for output fails if file exists Using file stream objects, methods and modes In this section we tie together the information presented in the previous sections. File I/O is a five step process 1. Include the appropriate header file. 2. Declare the file stream objects. 3. Use the open method to associate the file stream object with the appropriate input/output sources. 4. Use the file stream variables with <<, >> or other appropriate methods. 5. Close the files. When implementing the above steps it is helpful to note that A file has two names. Every input and output file used by a program has two names. The external file name is the real name of the file, but it is only used once when using the open method to connect the file to a stream. Afterwards, the file is referred to using its stream name. Example: Reading ordered pairs from an external data file. # include<iostream> # include<iomanip> # include<ifstream> using namespace std; int main( ) { // variable and object declarations int count; double x,y; ifstream fin; // open data file (exit program if unsuccessful) fin.open("xydata.txt"); if (fin.fail( )) { cout << "Unable to open the data file." << endl; exit(1); } // read ordered pair from data file and print to the screen count = 0; while (!fin.eof( )) { fin >> x >> y; cout << setw(5) << x << setw(5) << y << endl; count++; } // close the data file fin.close( ); return 0; } Example: Writing to a file. Note to append to the file rather than write over the file simply change the line fout.open("xydata.txt"); to fout.open("xydata.txt", ios::app); # include<iostream> # include<fstream> # include<iomanip> using namespace std; int main( ) { // object declaration ofstream fout; // open data file (exit program if unsuccessful fout.open("xydata.txt"); if (fout.fail( )) { cout << "Unable to open the file." << endl; exit(1); } // set the output file stream formats fout << setiosflags(ios::fixed) << setiosflags(ios::left) << setiosflags(ios::showpoint) << setprecision(2); // send data to file fout << setw(15) << "Batteries" << setw(10) << 39.95 << endl << setw(15) << "Bulbs" << setw(10) << 3.22 << endl << setw(15) << "Fuses" << setw(10) << 1.00 << endl; // close the data file fout.close( ); return 0; } Example: File streams as arguments # include<iostream> # include<iomanip> # include<fstream> using namespace std; void writeFile (ofstream &); int main( ) { ofstream outfile; writeFile(outfile); return 0; } void writeFile (ofstream &fout) { int i; char name[20]; cout << "Enter a filename. \n"; cin >> name; fout.open (name); for (i=1; i<=100; i++) { fout << setw(10) << i << setw(10) << i*i << endl; } return; } Example: Send message to the printer. # include<iostream> using namespace std; int main( ) { ofstream outfile; outfile.open(“prn”); outfile << “hello world \n”; return 0; }