490 likes | 648 Views
File I/O Version 1.0. Topics. I/O Streams File I/O Formatting Text Files Handling Stream Errors File Pointers. Objectives. After completing this topic, students should be able to:. Write programs that correctly read text data from a file,
E N D
Topics I/O Streams File I/O Formatting Text Files Handling Stream Errors File Pointers
Objectives After completing this topic, students should be able to: Write programs that correctly read text data from a file, handling file errors and end of file conditions appropriately. Write programs that correctly format and write text data to a file. Correctly use the C++ stream manipulation functions in a program
Input/Output Streams source We put data, as bytes, into an output stream We take data, as bytes, out of an input stream sink an ordered sequence of bytes
Standard I/O • cin – the standard input stream • cout – the standard output stream • cerr – the standard error stream These streams (objects) are automatically created for you when your program executes. To use them you only need to #include <iostream> and the using namespace std directive.
File I/O When a program takes input from a file, we say that it reads from the file. When a program puts data into a file, we say that it writes to the file. To read or write to a file, we create a stream object, and connect it to the file by opening it.
Text Files Data in a file can either be text or binary. Everything in a text file appears as readable characters. Text files are also referred to as Formatted or Sequential files.
The fstream classes We use objects of the ifstream class to read from a file, and objects of the ofstream class to write to a file. These classes are defined in <fstream>. To use them we must write #include <fstream> using namespace std;
ifstream Functions >> overloaded stream extraction operator get (ch) extract one character into ch get (str) extract characters into array str, until ‘\n’ get (str, MAX) extract up to MAX characters into array str get (str, DELIM)extract characters into array str until DELIM character is encountered. Leave DELIM character in buffer get (str, MAX, DELIM) these ought to look familiar, they are the same functions we use on standard In and standard Out.
Declaring Streams To use a stream object, it must first be declared ifstream inStream; ofstream outStream;
Stream variables A stream object is like any other variable, but there are some important exceptions: You cannot assign a value to a stream variable If you pass a stream variable as a parameter, you must pass it by reference or address.
Connecting a Stream to a File ifstream inputStream; inputStream.open (“theData.txt”); to program inputStream theData.txt Widget 123V89001 12.95 you can declare and connect to a file at the same time: ifstream inputStream (“theData.txt”);
Paths ifstream inputStream; inputStream.open (“theData.txt”); if no path is specified, the file is assumed to be in the same directory as the program that is executing. When you code a \ in a pathname, you must write \\. Why? inputStream.open (“c:\\theData.txt”);
Reading From a Text File To read from a text file, use the stream extraction operator, just as you would to read from the keyboard. string description; string partNumber; double price; ifstream inputStream; inputStream.open (“theData.txt”); … inputStream >> description >> partNumber >> price; …
Type Safe I/O In the C programming language, input and output are done with very different libraries than those used in C++ (Although you can still use the C I/O libraries in C++ if you want to). One of the advantages to using the new C++ libraries is that C++ I/O is typesafe. The << and >> operators are overloaded to do the correct thing for all of the standard data types. These operators can also be overloaded for user defined data types.
in the file, this is character data. inputStream theData.txt Widget 123V89001 12.95 12.95 convert from character to double …111000011010… double price; inputStream >> price; Data is read from the file and converted into the appropriate data type. price
Records and Fields Data in a text file is often organized into field and records. fields are usually separated by spaces, but may be separated by other delimiters, such as a comma or tab Widget 123V89001 12.95 \n Sprocket 456Y79321 21.50 \n Zagget 678H0032 32.25 \n Spoolbot 345W2311 3.23 \n … … records are usually separated by newline characters, but may be separated by other delimiters, such as semicolons. it is important to know how data in a file is organized, or it cannot be read. Keep in mind when the stream extraction operator stops reading!
Writing to a Text File Use the stream insertion operator to write to a text file, just as if you were writing to the display. ofstream outputStream; outputStream.open (“theData.txt”); … outputStream << price;
Opening an Output file If the named file does not exist, the file is created. If the named file already exists, it is opened, and the contents of the file are discarded, by default.
Formatting the Output Most of the time, when we write data to a file, it is with the idea in mind that the data will be read in from this or some other program. It is up to the programmer to format the data in the output file, so that it can later be read in a meaningful way.
Example int a = 5; int b = 15; int c = 239; ofstream myOutputStream (“mydata.txt”); myOutputStream << a << b << c; 515239 What happens when you try to read this file?
int a = 5; int b = 15; int c = 239; ofstream myOutputStream (“mydata.txt”); myOutputStream << a << “ “ << b << “ “ << c; add white space to separate the fields!
Closing the File It is good programming practice to close a file as soon as you are done using it. myOutputStream.close ( ); Although a file is (usually) closed automatically when a program ends normally, it is not closed if an error occurs and the program terminates abnormally. If the file is not closed, all of the data written to the file is lost!
Mode Bits When a file is opened, you can supply bits that further define the file. These mode bits are defined in the ios class. The ios class contains a number of important constants we use in file I/O. ios::in open the file for reading, the default for ifstream ios::out open the file for writing, the default for ofstream ios::app open the file for appending. All data is written at the end of the file ios::trunc open the file and discard contents, the default for ofstream ios::binary open the file for binary content, Note there is no ios::text which is the default
openmode Bits ios::app - seek to the end of a stream before each insertion. ios::ate - seek to the end of a stream when its controlling object is first created. ios::binary - read a file as a binary stream, rather than as a text stream. Default is text; however there is no ios::text mode bit. ios::in - permit extraction (read) from a stream. ios::out - permit insertion (write) to a stream. ios::trunc - delete contents of an existing file when its controlling object is created or create the file if it doesn’t exist.
Example #include <fstream> using namespace std; ofstream myOutputStream (“TheData.txt”, ios::app); …
Stream States Objects of all of the stream classes have a state that expresses the condition of the stream.. The stream classes provide functions to query the stream’s state. 2 1 0 bad fail eof good( ) Everything’s fine eof( ) An input operation tried to read beyond the end of the file fail( ) An input operation failed to read the expected character, or an output operation failed to generate the desired characters bad( ) Indicates the loss of integrity of the underlying input or output sequence rdstate( ) Returns all the stream state bits
Checking that a File Opened In C++, errors are not reported unless the programmer explicitly asks. For example, your program could call for a file to be opened and then read data from the file. If the file does not exist, no error is reported and you think that everything worked fine!
ifstreammyInputStream; myInputStream.open (“someData.txt”); if (myInputStream.rdstate( )!=0) { cout << “Could not open file”; } else { … check the state of the stream here… We could also write if (!myInputStream) {
Because I/O is subject to so many errors, it is good programming practice to check the state of the stream after every I/O operation!
Checking for End of File int theData; istream myFile; myFile.open (“someData.txt”); while (!myFile.eof( )) { myFile >> theData; … } Could also have written while (myFile >> theData) { … } when attempting to read past the end of the file, the eof( ) function returns true. But note that the condition is not checked until you go back to the while statement!
File Names as Input the filename must be stored in an array of characters. We will talk about char arrays in a later section… char fileName[80]; ifstream myData; cout << “Enter in a file name: “; cin >> fileName; myData.open (fileName); … Alternatively you could write string fileName; cin >> fileName; myData.open(fileName.c_str( ) );
Precision Precision refers to the number of digits after the decimal point. Every output stream has a member function named precision, that sets the precision of the data that goes into the file. outPutStream.precision ( 3 ); Precision stays as set until changed by another call to the precision function.
Formatting Flags Formatting flags are defined in the ios class. Stream classes have a member function, setf( flag ) that sets these formatting flags. left left align output not set right right align output set dec output as decimal set hex output as hexadecimal not set oct output as octal (base 8) not set showpoint show decimal point on output not set scientific output in exponential format not set fixed output in fixed format (not scientific) not set
You can combine flags with the | operator myStream.setf (ios::fixed | ios::showpoint); A flag remains set until it is unset. myStream.unsetf (ios::fixed);
Stream Manipulators Stream manipulators go directly into the stream. They are inserted using the stream insertion operator dec hex oct endl setw (w) setprecision (n); setiosflags (flags); setfill (fillChar); myStream << setw (5) << theData;
Side Effects You don’t want a function to have an unwanted side effect. One example would be setting I/O flags in a function and leaving them that way when you exit the function. The function flags returns a long data type that contains the settings of all of the I/O flags. long myFlags = myStream.flags ( ); … myStream.flags (myFlags); without an argument the function returns the flags. with an argument, the flags are restored to those set in the parameter.
File Pointers Streams have pointers associated with them get pointer points to the place next character will be read from put pointer points to where the next character will be written tellg( ) returns current get (read) file pointer tellp ( ) returns current put (write) file pointer seekg ( ) positions get (read) file pointer seekp ( ) positions put (write) file pointer
seekp (15); move 15 bytes from start of file (default) seekp (-10, ios::end); move -10 bytes from end of file seekg (6, ios::cur); move 6 bytes from current position
Updating Sequential Files When updating sequential files, you cannot depend on the size of a record always being the same. So, you must locate the position where you want to start writing, and then rewrite the remainder of the file.
Binary I/O Data is written to the output device exactly as it Is stored in memory. Binary I/O is done with the functions * read( ) * write( ) The parameters are the address of the data buffer and the number of bytes to read or write. The address must be cast to a char*
Example // buff is the address of an array of MAX integers… ofstreamos(“myData.dat”, ios::binary); os.write(reinterpret_cast<char*>(buff), MAX * sizeof(int) ); or os.write((char*)buff, MAX * sizeof(int) ); os.close( ); reinterpret cast tells the compiler that you want to do this cast, even though it might not make sense to the compiler.
… 100110… …10100 buff buff + MAX
#include <iostream> using namespace std; int main( ) { int anInteger; // temp holding place for input do { cout << "\nType an integer ( 0 to quit ):"; cin >> anInteger; cout << "You typed " << anInteger; } while ( anInteger != 0 ); return 0; }
Handling I/O Errors – An Example int main( ) { int anInteger; // temp holding place for input do { cout << "\nType an integer ( 0 to quit ):"; if ( cin >> anInteger ) { cout << "You typed " << anInteger; } else { cout << "\nBad input ... Integer expected!"; cin.clear ( ); cin.sync ( ); } } while ( anInteger != 0 ); return 0; }
Practice Given: You have a file of student grades on your c: drive. The path to the file is c:\grades.txt The file is a text file. Write the statement that declares the input stream object mydata, opens the file, and connects it to the stream object.
Practice Write the code that tests to see if the file opened successfully. If it did not open, output a message to the user.
Practice Now . . . Put all of this code in a loop that 1) Prompts the user for a file name 2) Creates the stream object and tries to open the file 3) Tests to see if the file opened successfully 4) If it did not open send a message to the user to a) exit the program, or b) type in a different file name c) accept only valid choices in response 5) When the file opens, tell the user hint: draw an activity diagram first!
Practice The file contains a set of integers, with one integer on each line of the file. We want to add up all of the value in the file. Write a loop that will read each integer value from the file and add it to a variable myData. You do not know how much data is in the file. Print a message to the user if any read operation fails because of bad data.