Like C, the C++ language does not have input/output access built into the language. IO is achieved by using external library functions. A library is a collection of object files that can be linked to a program to provide additional functionality.
C++ IO is based on streams, which encapsulate the data flow in and out of input and output devices. With input operations, data bytes flow from an input source such as a keyboard or file into the program. In output operations, data flows from the program to an output destination such as a console or file.
Some of the more common stream classes included in C++ are
fstream - Stream class to both read and write from/to files..Inherits from ofstream and ifstream.
cout - Standard output stream. Typically redirected to the console.
cin - Standard input stream. Typically used to read data from the console
ofstream - Stream output class typically used to write to files
ifstream - Stream input class typically used to read files
cerr - standard output stream for errors
cin
The global object cin is an object is used to handle input. It is found in the iostream header file. The cin object is used with the extraction operator (>>) to receive a stream of characters. The general syntax is:
cin >> varName;
The extraction operator can be used more than once to accept multiple inputs as:
cin >> var1 >> var2 >> var3;
Inputting Strings
Cin can also accept character pointer ( char* ) arguments by creating and filling a character buffer -
char userName[50] cout << “Enter name: “; cin >> userName;
The username in the above example will contain the characters entered at the keyboard terminated by the null character (\0) which signals the end of the string. The buffer must have enough room for the entire string plus the null. A space or new line, signifies the end of the input, and a null character is inserted.
Some additional member function of cin
cin.get() - returns the first value of the character in an input sequence
cin.get( pCharArray, StreamSize, TermChar ) - is used to fill a character array. the first parameter is a pointer to that character array, the second parameter is the maximum of characters that can be read, and the 3rd is the termination character
cin.ignore(nCount,delim) - extracts and discards up to nCount characters. Extraction stops if the delimiter delim is extracted or the end of the file is reached.
cin.peek() - returns the next character in the input sequence, without extracting it.
cin.putback() - puts the last character extracted from the input stream by the get() function back into the input stream.
The code sample below demonstrates different ways of using the cin function.
#include <iostream> using namespace std; int main() { char YourName[50]; int age; cout << "Enter your name and age separated by a space "; cin >> YourName>>age;//Separating input using a space has the same effect as using return cin.ignore();//used to clear input stream cout << "Your name is "<< YourName << " and you age is " << age << std::endl; char a,b,c; std::cout << "Enter 3 letters "; std::cin.get(a).get(b).get(c);//reads in 3 characters cin.ignore(); cout << a << endl << b << endl << c << endl; std::cout << "Enter your favourite colour (max 20 characters)"; char word[20]; cin.get(word, 20);//reads first 20 characters in input stream cout << "you favourite colour is " << word << endl; return 0; }
cout
The global object cout is an object of class ostream and with the overloaded insertion operator ( << ) is used to handle the output. It is found in the iostream header file. The general syntax is:
cout << value;
Or
cout << "string value";
The extraction operator can be used more than once with a combination of values:
cout << value1 << "String" << value2 << endl;
Some Additional Member Functions of cout
cout.put(char c) - used to write a single character to the output device.
cout.write(const *char, int n) - works similarly to the insertion operator ( << ) except that the parameter n tells the function the number of characters to write
cout.setf(option) - sets a format flag.
cout.unsetf(option) - clears a format flag.
cout.precision(int n): - sets the decimal precision to n while displaying floating-point values
#include <iostream> #include <iomanip> using namespace std; int main() { cout.put('H').put('e').put('l').put('l').put('o').put('\n'); char message[]="Hello world"; cout.write(message, 11) << "\n"; cout << "position 1"; cout.width(30); cout << "position 2"; cout.width(30); cout << "position 3"; cout << "\n"; cout.setf(ios::showpos); float value=22; cout.precision(3); cout << "the value of pi to 2dp="<< value/7 << endl; int hexvalue=10; cout.setf(ios_base::hex|ios_base::uppercase) ; cout <<"the value of 10 in hex is " << hex << hexvalue; return 0; }
File Input and Output
C++ provides the following classes to perform input and output to and from files:
ofstream: Stream class to write on files
ifstream: Stream class to read from files
fstream: Stream class to both read and write from/to files.
Before any file ofstream or ifstream object is created, the stream must be associated with a particular file. The iostream objects maintain various flags that report on the status of the file operations.
Opening Files for Input and Output
To open a file for output with the ofstream object, declare an instance of an ofstream object and pass in the filename as a parameter -
ofstream fout(“filename.cpp”);
To open a file for input with the ifstream object, declare an instance of an ifstream object and pass in the filename as a parameter -
#include <fstream> #include <iostream> using namespace std; int main() { char fileName[80]="myfile"; char filebuffer[255]; ofstream fout(fileName); // open for file writing data cout << "Enter some text to store in the file: "; cin.getline(filebuffer,255); // get the user input fout << filebuffer << "\n";// write input to the file fout.close(); // close the file, ready for reopen ifstream fin(fileName); // reopen for reading cout << "The contents of your file are:\n"; char ch; while (fin.get(ch)) cout << ch; fin.close(); return 0; }
File Opening Modes
A file can be opened in different modes to perform read and write operations.
These are -
Mode | Explanation |
ios :: in | Open a file for reading |
ios :: out | Open a file for writing |
ios :: app | Appends data to the end of the file |
ios :: ate | File pointer moves to the end of the file but allows data to be written to any location in the file |
ios :: binary | Binary File |
ios :: trunc | Deletes the contents of the file before opening |
The default behaviour when using ofstream to open a file is to create a file if it does not exist and to delete or truncate all its contents.
The following worked example requests some text from the user and stores that data in a new file on disk. The data on the file is then read and printed in the console
In the sample code below the program first checks for the existence of 'myfile'. If the file does not exist the user is asked to enter some data. If the file exists the user is asked whether they want to replace or amend the contents. The contents are then output to the console
#include <fstream> #include <iostream> using namespace std; int main() { char fileName[80]="myfile"; char filebuffer[255]=""; char response='y'; ifstream fin(fileName); // open for file writing data if (fin) // check if file already exists? { cout << "File already exists. Do you wish to replace file contents y/n"; cin >> response; fin.close(); } if (response=='y') { ofstream fout(fileName,ios::trunc); // open for file writing data.replace contents cout << "Enter some text to store in the file: "; cin.ignore(); cin.getline(filebuffer,255); fout << filebuffer<< endl;// write input to the file fout.close(); } else { ofstream fout(fileName,ios_base::out|ios::app); //open file and append data cout << "Enter some text to add to the file: "; cin.ignore(); cin.getline(filebuffer,255); // get the user input fout << filebuffer << endl;// write input to the file fout.close(); } fin.open(fileName); // reopen for reading cout << "The contents of your file are:\n "; char ch; while (fin.get(ch)) { cout << ch; } fin.close(); return 0; }
Checking I/O state flags
The following member functions exist to check for specific states of a stream. All return bool value:
bad() - returns true if a reading or writing operation fails. For example, trying to write to a file that is not open.
fail() - detects whether the value entered fits the value defined in the variable.
eof() - returns true if a file open for reading has reached the end.
good() - checks whether the state of the stream is good. Returns true if none of the stream's error state flags are set
clear() - used to reset the state flags.
Binary files
Text files store everything as text in a human-readable format. This can be inefficient but has the advantage that the text can be read using programs such as simple text editors. A binary file contains a sequence of bytes not in a human-readable format. The process of writing to a binary file is similar to writing to a text file with the exception that the file I/O object must stipulate ios_base::binary flag as a mask when opening the file.
A binary file stream object can be opened as follows
ifstream myFile ("myfile.bin", ios::in | ios::binary);
or by call to its open methods after the file stream object has been instantiated
ofstream myFile;
myFile.open ("myfile.bin", ios::out | ios::binary);
Writing to and reading from a binary file
In general, there are two ways to write and read unformatted binary data to or from a file. Data can be written to a file using the member function put(), and read using the member function get(). Alternatively, a program can read and write to a binary file using the block access I/O functions: read() and write()
The code section below indicates how the get() function can be overloaded in several different ways to read data-
#include <fstream> #include <iostream> using namespace std; int main() { char *message = "hello world"; char ch; char buffer[12]="buffer"; //create file test ofstream out("test", ios::out | ios::binary); if(!out) { cout << "Cannot open file.\n"; return 1; } //write contents of message to file while(*message) out.put(*message++); out.close(); ifstream in("test", ios::in | ios::binary); if(!in) { cout << "Cannot open file.\n"; return 1; } //read in file contents and write out to screen while(in) { //false when eof is reached in.get(ch); if(in) cout << ch; } in.clear(); in.seekg(0);//move pointer to start of file in.get(buffer,12);//get first 12 characters in file cout << endl << buffer << endl; in.clear(); in.seekg(0); in.get(buffer,12,' ');//read in characters after space cout << buffer << endl; in.clear(); in.seekg(6);//move pointer to position 6 in file in.getline(buffer,12,'\n');//read in character upto new line cout << buffer << endl; return 0; }
The code function below illustrates reading and writing to a binary file using the block access I/O functions: read( ) and write( )
#include <fstream> #include <iostream> using namespace std; int main() { int array[5] = {10, 20, 30, 40, 50}; int i; ofstream out("myfile", ios::out | ios::binary); if(!out) { cout << "Cannot open file.\n"; return 1; } out.write((char *) &array, sizeof array); out.close(); for(i=0; i<5; i++) // clear array array[i] = 0; ifstream in("myfile", ios::in | ios::binary); if(!in) { cout << "Cannot open file.\n"; return 1; } in.read((char *) &array, sizeof array); for(i=0; i<5; i++) // show values read from file cout << array[i] << " "; in.close(); return 0; }
Random Access
In addition to reading or writing files sequentially, file data can be accessed in random order using the seekg( ) and seekp( ) functions. The C++ I/O system manages two pointers associated with a file. One is the get pointer and the other is the put pointer. The put pointer specifies where the next file input operation will occur. The get pointer specifies where the next file output operation will occur. Each time an input or an output operation occurs, the appropriate pointer is automatically adjusted. Using the seekg( ) and seekp( ) functions, it is possible to adjust these pointer values in a non-sequential fashion. The seekg( ) function moves the file’s get pointer and the seekp( ) function moves the file’s put pointer.
In the sample code below a file is created and text added. The position of the put and get pointers is reported using the seekg and seekp method.
#include <fstream> #include <iostream> using namespace std; int main() { char buffer[40] = ""; fstream data; data.open ("myfile", ios::in | ios::out );//open fstream for input and output int newpos=data.tellp();//get position of put pointer at start cout << buffer <<"position of put pointer at start " << newpos << endl; data.write("hello world", 11);//write data to file newpos = data.tellp();//get position of put pointer cout << buffer <<"position of put pointer of first write " << newpos << endl; data.seekg(0); //reposition get pointer to start of file newpos = data.tellp();//get position of put pointer after adding text cout << buffer <<"position get pointer at start of file " << newpos << endl; data.read(buffer, 11);//read file data to buffer cout <<"file contents - " << buffer << endl; newpos = data.tellp();//get position of put pointer cout <<"position of get pointer after reading from file " << newpos << endl; data.write(" from me", 9);//add new string to end of file newpos = data.tellp();//get position of put pointer cout <<"position of put pointer after 2nd write " << newpos << endl; data.seekg(0); //reposition get pointer to start of file data.read(buffer, 19);//read file data to buffer cout << buffer; return 0; }