Oop Mod5@Azdocuments - in
Oop Mod5@Azdocuments - in
Table of Contents
C++ provides both the formatted and unformatted IO functions. In formatted or high-level IO, bytes are grouped
and converted to types such as int, double, string or user-defined types. In unformatted or low-level IO, bytes are
treated as raw bytes and unconverted. Formatted IO operations are supported via overloading the stream insertion
(<<) and stream extraction (>>) operators, which presents a consistent public IO interface.
2. Connect (Associate) the stream object to an actual IO device (e.g., keyboard, console, file, network,
another program).
3. Perform input/output operations on the stream, via the functions defined in the stream's pubic
interface in a device independent manner. Some functions convert the data between the external
format and internal format (formatted IO); while other does not (unformatted or binary IO).
4. Disconnect (Dissociate) the stream to the actual IO device (e.g., close the file).
Template Classes
In order to support various character sets (char and wchar_t in C++98/03; and char16_t, char32_t introduced in
C++11), the stream classes are written as template classes, which could be instantiated with an actual character
type. Most of the template classes take two type parameters. For example,
template <class charT, class traits = char_traits<charT> >
class basic_istream;
where:
Take note that cin/cout shall be the left operand and the data flow in the direction of the arrows.
The << and >> operators are overloaded to handle fundamental types (such as int and double), and classes (such
as string). You can also overload these operators for your own user-defined types.
The cin << and cout >> return a reference to cin and cout, and thus, support cascading operations. For example,
The << operator returns a reference to the invoking ostream object. Hence, you can concatenate << operations,
e.g., cout << 123 << 1.13 << endl;.
The << operator is also overloaded for the following pointer types:
const char *, const signed char *, const unsigned char *: for outputting C-strings and literals. It uses the
terminating null character to decide the end of the char array.
void *: can be used to print an address.
For example,
11. endl manipulator, which inserts a newline and flush the buffer. Outputting a newline
character '\n' may not flush the output buffer; but endl does.
cin << number; // flush output buffer so as to show the prompting message
The >> operator returns a reference to the invokind istream object. Hence, you can concatenate >> operations,
e.g., cin >> number1 << number2 <<....
The >> operator is also overloaded for the following pointer types:
const char *, const signed char *, const unsigned char *: for inputting C-strings. It uses whitespace as
delimiter and adds a terminating null character to the C-string.
// Examples
cin.ignore(numeric_limits<streamsize>::max()); // Ignore to the end-of-file
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // Ignore to the end-of-line
// ostream class
ostream & put (char c); // put char c to ostream
// Examples
cout.put('A');
cout.put('A').put('p').put('p').put('\n');
cout.put(65);
// istream class
// Single character input
int get ();
// Get a char and return as int. It returns EOF at end-of-file
istream & get (char & c);
// Get a char, store in c and return the invoking istream reference
// C-string input
istream & get (char * cstr, streamsize n, char delim = '\n');
// Get n-1 chars or until delimiter and store in C-string array cstr.
// Append null char to terminate C-string
// Keep the delim char in the input stream.
istream & getline (char * cstr, streamsize n, char delim = '\n');
// Same as get(), but extract and discard delim char from the
// input stream.
// Examples
int inChar;
while ((inChar = cin.get()) != EOF) { // Read till End-of-file
cout.put(inchar);
}
[TODO] Example
// istream class
istream & read (char * buf, streamsize n);
// Read n characters from istream and keep in char array buf.
// Unlike get()/getline(), it does not append null char at the end of input.
// It is used for binary input, instead of C-string.
streamsize gcount() const;
// Return the number of character extracted by the last unformatted input operation
// get(), getline(), ignore() or read().
// ostream class
ostream & write (const char * buf, streamsize n)
// Write n character from char array.
// Example
[TODO]
States of stream
The steam superclass ios_base maintains a data member to describe the states of the stream, which is a bitmask of
the type iostate. The flags are:
eofbit: set when an input operation reaches end-of-file.
failbit: The last input operation failed to read the expected characters or output operation failed to
write the expected characters, e.g., getline() reads n characters without reaching delimiter character.
badbit: serious error due to failure of an IO operation (e.g. file read/write error) or stream buffer.
goodbit: Absence of above error with value of 0.
These flags are defined as public static members in ios_base. They can be accessed directly via ios_base::failbit or
via subclasses such as cin::failbit, ios::failbit. However, it is more convenience to use these public member functions
of ios class:
good(): returns true if goodbit is set (i.e., no error).
eof(): returns true if eofbit is set.
fail(): returns true if failbit or badbit is set.
bad(): returns true if badbit is set.
clear(): clear eofbit, failbit and badbit.
By default, the values are displayed with a field-width just enough to hold the text, without additional
leading or trailing spaces. You need to provide spaces between the values, if desired.
cout << "|" << -123456789 << "|" << endl; // |-123456789|
For floating-point numbers, the default precison is 6 digits, except that the trailing zeros will not be
shown. This default precision (of 6 digits) include all digits before and after the decimal point, but
exclude the leading zeros. Scientific notation (E-notation) will be used if the exponent is 6 or more or
-5 or less. In scientific notation, the default precision is also 6 digits; the exponent is displayed in 3
digits with plus/minus sign (e.g., +006, -005). For example,
cout << "|" << 1.20000 << "|" << endl; // |1.2| (trailing zeros not displayed)
cout << "|" << 1.23456 << "|" << endl; // |1.23456| (default precision is 6 digits)
cout << "|" << -1.23456 << "|" << endl; // |-1.23456|
cout << "|" << 1.234567 << "|" << endl; // |1.23457|
cout << "|" << 123456.7 << "|" << endl; // |123457|
cout << "|" << 1234567.89 << "|" << endl; // |1.23457e+006| (scientific-notation for e>=6)
cout << "|" << 0.0001234567 << "|" << endl; // |0.000123457| (leading zeros not counted towards precision)
cout << "|" << 0.00001234567 << "|" << endl; // |1.23457e-005| (scientific-notation for e<=-5)
The internal alignment left-align the sign, but right-align the number, as illustrated.
You can also use ostream's member function width() (e.g. cout.width(n)) to set the field width, but width() cannot be
used with cout << operator.
Floating-point Format (fixed|scientific) and Precision (setprecision)
The IO stream superclass ios_base also maintains data member for the floating-point precision and display format;
and provides member functions (such as precision()) for manipulating them.
Again, it is more convenience to use IO manipulators, which can be concatenated in <<. They are:
setprecision() manipulator (in <iomanip> header) to set the precision of floating-point number.
fixed|scientific manipulators (in <iostream> header) to set the floating-point display format.
Floating point number can be display in 3 formatting modes: default|fixed|scientific. The precision is interpreted
differently in default and non-default modes (due to legacy).
In default mode (neither fixed nor scientific used), a floating-point number is displayed in fixed-point
notation (e.g., 12.34) for exponent in the range of [-4, 5]; and scientific notation (e.g., 1.2e+006)
otherwise. The precision in default mode includes digits before and after the decimal point but
exclude the leading zeros. Fewer digits might be shown as the trailing zeros are not displayed. The
default precision is 6. See the earlier examples for default mode with default precision of 6.
As mentioned, the trailing zeros are not displayed in default mode, you can use
manipulator showpoint|noshowpoint to show or hide the trailing zeros.
In both fixed (e.g., 12.34) and scientific (e.g., 1.2e+006), the precision sets the number of digits after
decimal point. The default precision is also 6.
For examples,
// fixed-point formatting
cout << fixed;
cout << "|" << 1234567.89 << "|" << endl; // |1234567.890000|
// default precision is 6, i.e., 6 digits after the decimal point
// scientific formatting
cout << scientific;
cout << "|" << 1234567.89 << "|" << endl; // |1.234568e+006|
// default precision is 6, i.e., 6 digits after the decimal point
// Test precision
cout << fixed << setprecision(2); // sticky
cout << "|" << 123.456789 << "|" << endl; // |123.46|
cout << "|" << 123. << "|" << endl; // |123.00|
You can also use ostream's member function precision(n) (e.g. cout.precision(n)) to set the floating-point precision,
but precision() cannot be used with cout << operator.
Integral Number Base (dec|oct|hex, setbase)
C++ support number bases (radixes) of decimal, hexadecimal and octal. You can use the following manipulators
(defined in ios_base class, included in <iostream> header) to manipulate the integral number base:
hex|dec|oct: Set the integral number base. Negative hex and oct are displayed in 2's complement
format. Alternatively, you can use setbase(8|10|16) (in header <iomanip>).
showbase|noshowbase: write hex values with 0x prefix; and oct values with 0 prefix.
showpos|noshowpos: write positive dec value with + sign.
uppercase|nouppercase: write uppercase in certain insertion operations, e.g., hex digits. It does not
convert characters or strings to uppercase!
These manipulators are sticky.
For examples,
cout << 1234 << endl; // 1234 (default is dec)
cout << hex << 1234 << endl; // 4d2
cout << 1234 << "," << -1234 << endl; // 4d2,fffffb2e
// (hex is sticky, negative number in 2's complement)
cout << oct << 1234 << endl; // 2322
cout << 1234 << "," << -1234 << endl; // 2322,37777775456
cout << setbase(10) << 1234 << endl; // 1234 (setbase requires <iomanip> header)
cout << noboolalpha << false << "," << true << endl; // 0,1
Other manipulators
skipws|noskipws: skip leading white spaces for certain input operations.
unitbuf|nounibuf: flush output after each insertion operation.
Notes
You need to include the <iomanip> header for setw(), setprecision(), setfill(), and setbase().
You can use ios_base's (in <iostream> header) member functions setf() and unsetf() to set the individual
formatting flags. However, they are not as user-friendly as using manipulators as discussed above.
Furthermore, they cannot be used with cout << operator.
The C++ string class Input/Output
File IO requires an additional step to connect the file to the stream (i.e., file open) and disconnect from the stream
(i.e., file close).
File Output
2. Connect it to a file (i.e., file open) and set the mode of file operation (e.g, truncate, append).
3. Perform output operation via insertion >> operator or write(), put() functions.
4. Disconnect (close the file which flushes the output buffer) and free the ostream object.
#include <fstream>
.......
ofstream fout;
fout.open(filename, mode);
......
fout.close();
By default, opening an output file creates a new file if the filename does not exist; or truncates it (clear its content)
and starts writing as an empty file.
void close (); // Closes the file, flush the buffer and disconnect from stream object
File Modes
File modes are defined as static public member in ios_base superclass. They can be referenced from ios_base or its
subclasses - we typically use subclass ios. The available file mode flags are:
1. ios::in - open file for input operation
2. ios::out - open file for output operation
3. ios::app - output appends at the end of the file.
4. ios::trunc - truncate the file and discard old contents.
5. ios::binary - for binary (raw byte) IO operation, instead of character-based.
6. ios::ate - position the file pointer "at the end" for input/output.
You can set multiple flags via bit-or (|) operator, e.g., ios::out | ios::app to append output at the end of the file.
For output, the default is ios::out | ios::trunc. For input, the default is ios::in.
File Input
2. Connect it to a file (i.e., file open) and set the mode of file operation.
3. Perform output operation via extraction << operator or read(), get(), getline() functions.
4. Disconnect (close the file) and free the istream object.
#include <fstream>
.......
ifstream fin;
fin.open(filename, mode);
......
fin.close();
// OR combine declaration and open()
ifstream fin(filename, mode);
Program Notes:
Most of the <fstream> functions (such as constructors, open()) supports filename in C-string only. You
may need to extract the C-string from string object via the c_str() member function.
You could use is_open() to check if the file is opened successfully.
The get(char &) function returns a null pointer (converted to false) when it reaches end-of-file.
Binary file, read() and write()
We need to use read() and write() member functions for binary file (file mode of ios::binary), which read/write raw
bytes without interpreting the bytes.
Random access file is associated with a file pointer, which can be moved directly to any location in the file.
Random access is crucial in certain applications such as databases and indexes.
You can position the input pointer via seekg() and output pointer via seekp(). Each of them has two versions:
absolute and relative positioning.
Random access file is typically process as binary file, in both input and output modes.
[TODO] Example
String Streams
C++ provides a <sstream> header, which uses the same public interface to support IO between a program
and string object (buffer).
The string streams is based on ostringstream (subclass of ostream), istringstream (subclass of istream) and bi-
directional stringstream (subclass of iostream).
Stream input can be used to validate input data; stream output can be used to format the output.
ostringstream
For example,
// Get contents
cout << sout.str() << endl;
C++ provides a list of standard exceptions defined in <exception> which we can use in our
programs. These are arranged in an a parent-child class hierarchy shown below:
Here is the small description of each exception mentioned in the above hierarchy:
Exception Description
std::exception An exception and parent class of all the standard C++ exceptions.
std::out_of_range This can be thrown by the at method from for example a std::vector and
std::bitset<>::operator[]().
std::runtime_error An exception that theoretically can not be detected by reading the code.
std::range_error This is occured when you try to store a value which is out of range.
You can define your own exceptions by inheriting and overriding exception class functionality.
Following is the example which shows how you can use std::exception class to implement your own
exception in standard way:
#include <iostream>
#include <exception>
using namespace std;
struct MyException : public exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
};
int main()
{
try
{
throw MyException();
}
catch(MyException& e)
{
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
}
catch(std::exception& e)
{
//Other errors
}
}
Here what() is a public method provided by exception class and it has been overridden by all the
child exception classes. This returns the cause of an exception.
Create an Input Stream
To create an input stream, you must declare the stream to be of class ifstream. Here is the syntax:
ifstream fin;
To create an output stream, you must declare it as class ofstream. Here is an example:
ofstream fout;
Streams that will be performing both input and output operations must be declared as class fstream.
Here is an example:
Once a stream has been created, next step is to associate a file with it. And thereafter the file is
available (opened) for processing.
The first method is preferred when a single file is used with a stream. However, for managing
multiple files with the same stream, the second method is preferred. Let's discuss each of these
methods one by one.
We know that a constructor of class initializes an object of its class when it (the object) is being
created. Same way, the constructors of stream classes (ifstream, ofstream, or fstream) are used to
initialize file stream objects with the filenames passed to them. This is carried out as explained here:
To open a file named myfile as an input file (i.e., data will be need from it and no other operation like
writing or modifying would take place on the file), we shall create a file stream object of input type
i.e., ifstream type. Here is an example:
ifstream fin("myfile", ios::in) ;
The above given statement creates an object, fin, of input file stream. The object name is a user-
defined name (i.e., any valid identifier name can be given). After creating the ifstream object fin, the
file myfile is opened and attached to the input stream, fin. Now, both the data being read from myfile
has been channelised through the input stream object.
Now to read from this file, this stream object will be used using the getfrom operator (">>"). Here is
an example:
char ch;
fin >> ch ; // read a character from the file
float amt ;
fin >> amt ; // read a floating-point number form the file
Similarly, when you want a program to write a file i.e., to open an output file (on which no operation
can take place except writing only). This will be accomplish by
Here is an example,
This would create an output stream, object named as fout and attach the file secret with it.
Now, to write something to it, you can use << (put to operator) in familiar way. Here is an example,
The connections with a file are closed automatically when the input and the output stream objects
expires i.e., when they go out of scope. (For example, a global object expires when the program
terminates). Also, you can close a connection with a file explicitly by using the close() method :
There may be situations requiring a program to open more than one file. The strategy for opening
multiple files depends upon how they will be used. If the situation requires simultaneous processing
of two files, then you need to create a separate stream for each file. However, if the situation
demands sequential processing of files (i.e., processing them one by one), then you can open a single
stream and associate it with each file in turn. To use this approach, declare a stream object without
initializing it, then use a second statement to associate the stream with a file. For example,
The above code lets you handle reading two files in succession. Note that the first file is closed
before opening the second one. This is necessary because a stream can be connected to only one file
at a time.
The filemode describes how a file is to be used : to read from it, to write to it, to append it, and so on.
When you associate a stream with a file, either by initializing a file stream object with a file name or
by using the open() method, you can provide a second argument specifying the file mode, as
mentioned below :
stream_object.open("filename", (filemode) ) ;
The second method argument of open(), the filemode, is of type int, and you can choose one from
several constants defined in the ios class.
Following table lists the filemodes available in C++ with their meaning :
This value causes the contents of a pre-existing file by the same name
ios :: trunc ofstream
to be destroyed and truncates the file to zero length.
This cause the open() function to fail if the file does not already exist.
ios :: nocreate ofstream
It will not create a new file with that name.
This causes the open() function to fail if the file already exists.
ios :: noreplace ofstream
This is used when you want to create a new file and at the same time.
The fstream class does not provide a mode by default and, therefore, one must specify the mode
explicitly when using an object of fstream class.
Both ios::ate and ios::app place you at the end of the file just opened. The difference between the two
is that the ios::app mode allows you to add data to the end of the file only, when the ios::ate mode
lets you write data anywhere in the file, even over old data.
You can combine two or more filemode constants using the C++ bitwise OR operator (symbol |). For
example, the following statement :
ofstream fout;
fout.open("Master", ios :: app | ios :: nocreate);
will open a file in the append mode if the file exists and will abandon the file opening operation if the
file does not exist.
To open a binary file, you need to specify ios :: binary along with the file mode, e.g.,
or,
As already mentioned, a file is closed by disconnecting it with the stream it is associated with. The
close() function accomplishes this task and it takes the following general form :
stream_object.close();
For example, if a file Master is connected with an ofstream object fout, its connections with the
stream fout can be terminated by the following statement :
fout.close() ;
#include<conio.h>
#include<string.h>
#include<stdio.h>
#include<fstream.h>
#include<stdlib.h>
void main()
{
ofstream fout;
ifstream fin;
char fname[20];
char rec[80], ch;
clrscr();
fout.open(fname, ios::out);
if(!fout)
{
cout<<"Error in opening the file "<<fname;
getch();
exit(1);
}
cin.get(ch);
fin.open(fname, ios::in);
if(!fin)
{
cout<<"Error in opening the file "<<fname;
cout<<"\nPress any key to exit...";
getch();
exit(2);
}
cin.get(ch);
fin.get(rec, 80);
cout<<"\nThe file contains:\n";
cout<<rec;
cout<<"\n\nPress any key to exit...\n";
fin.close();
getch();
}
EOD of File
so, just how much data is in that file? The exact contents of a file may not be precisely known.
Usually the general format style of the file and the type of data contained within the file are
known.
The amount of data stored in the file, however, is often unknown. So, do we spend our time
counting data in a text file by hand, or do we let the computer deal with the amount of data? Of
course, we let the computer do the counting.
C++ provides a special function, eof( ), that returns nonzero (meaning TRUE) when there are no
more data to be read from an input file stream, and zero (meaning FALSE) otherwise.
1. Always test for the end-of-file condition before processing data read from an input file
stream.
a. use a priming input statement before starting the loop
b. repeat the input statement at the bottom of the loop body
2. Use a while loop for getting data from an input file stream. A for loop is desirable only when
you know the exact number of data items in the file, which we do not know.
#include <fstream.h>
#include <assert.h>
int main(void)
{
int data; // file contains an undermined number of integer values
ifstream fin; // declare stream variable name
The eof( ) function has been known to be persnickety under certain conditions. If you experience pro
may want to consider this alternate approach to check for end of file:
int main(void)
{
ofstream fout;
ifstream fin;
apstring sentences, sent;
2.
3.
4.
5.
6.