Introduction to C++ IO Streams

Introduction to C++ IO Streams
The C++ standard libraries provide an extensive set of input/output capabilities which we will see in subsequent chapters. This chapter will discuss very basic and most common I/O operations required for C++ programming.
C++ I/O occurs in streams, which are sequences of bytes. If bytes flow from a device like a keyboard, a disk drive, or a network connection etc. to main memory, this is called input operation and if bytes flow from main memory to a device like a display screen, a printer, a disk drive, or a network connection, etc, this is called output operation.
IOstreams can be used for a wide variety of data manipulations to the following features:
* A 'stream' is internally nothing but a series of characters. The characters may be either normal characters (char) or wide characters (wchar_t). Streams provide you with a universal character-based interface to any type of storage medium (for example, a file), without requiring you to know the details of how to write to the storage medium. Any object that can be written to one type of stream, can be written to all types of streams. In other words, as long as an object has a stream representation, any storage medium can accept objects with that stream representation.
* Streams work with built-in data types, and you can make user-defined types work with streams by overloading the insertion operator (<<) to put objects into streams, and the extraction operator (>>) to read objects from streams.
* The stream library's unified approach makes it very friendly to use. Using a consistent interface for outputting to the screen and sending files over a network makes life easier. The programs below will show you what is possible.
Input and Output
The programmer, whether you want the input to be a number, to be a string, or to be fodder for /dev/random; whether the characters can be valid for the desired type totally depends upon whether that type can interpret the characters in the input stream as a description for an object of that type.
You have to get the input characters into a recognizable data type for them to be of any use other than as a character array.
IO streams not only define the relation between a stream of characters and the standard data types but also allows you to define a relationship between a stream of characters and your own classes. It also allows you nearly limitless freedom to manipulate those streams both using object oriented interfaces and working directly on character buffers when necessary. (Of course some of the lower level manipulations may be undefined; for example, you can't probe forward into an input stream to see the future!).
streams
Streams are serial interfaces to storage, buffers files, or any other storage medium. The difference between storage media is intentionally hidden by the interface; you may not even know what kind of storage you're working with but the interface is exactly the same.
The "serial" nature of streams is a very important element of their interface. You cannot directly make random access random reads or writes in a stream (unlike, say, using an array index to access any value you want) although you can seek to a position in a stream and perform a read at that point.
Using a serial representation gives a consistent interface for all devices. Many devices have the capability of both producing and consuming data at the same time; if data is being continually produced, the simplest way to think about reading that data is by doing a fetch of the next characters in a stream. If that data hasn't been produced yet (the user hasn't typed anything, or the network is still busy processing a packet), you wait for more data to become available, and the read will return that data. Even if you try to seek past the end (or beginning) of a stream, the stream pointer (i.e. get or put pointer) will remain at the boundary, making the situation safe. (Compare this with accessing data off the end of an array, where the behavior is undefined.)
The underlying low-level interface that corresponds to the actual medium very closely is a character buffer (the stream buffer, technically called the streambuf), which can be thought of as the backbone of the stream. Being a buffer, it does not hold the entire content of the stream, if the stream is large enough, so you can't use it for random access.
The most important of the basic stream operations are:
1. First, the stream is initialized with the appropriate type (like a std::string for a stringstream and the filename for an fstream) of values and suitable modes (like ios::in for input and ios::out for output and many more depending on the type of the stream).
2. After that, you can specify where the I/O should occur, through the get and put pointers. Depending on how you open the stream, the location may already be set appropriately (for example, if you open a file with ios::app, your get pointer set at the end of the stream, allowing appends).
Input/output with files & Library
C++ provides the following classes to perform output and input of characters to/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.
These classes are derived directly or indirectly from the classes istream and ostream. We have already used objects whose types were these classes: cin is an object of class istream and cout is an object of class ostream. Therefore, we have already been using classes that are related to our file streams. And in fact, we can use our file streams the same way we are already used to use cin and cout, with the only difference that we have to associate these streams with physical files.

The iostream library is an object-oriented library that provides input and output functionality using streams.
A stream is an abstraction that represents a device on which input and ouput operations are performed. A stream can basically be represented as a source or destination of characters of indefinite length.
Streams are generally associated to a physical source or destination of characters, like a disk file, the keyboard, or the console, so the characters gotten or written to/from our abstraction called stream are physically input/output to the physical device. For example, file streams are C++ objects to manipulate and interact with files; Once a file stream is used to open a file, any input or output operation performed on that stream is physically reflected in the file. To operate with streams, C++ provides the standard iostream library, which contains the following elements:
Basic class templates
* The base of the iostream library is the hierarchy of class templates. The class templates provide most of the functionality of the library in a type-independent fashion.
* This is a set of class templates, each one having two template parameters: the char type (charT) parameter, that determines the type of elements that are going to be manipulated and the traits parameter, that provides additional characteristics specific for a particular type of elements.
* The class templates in this class hierarchy have the same name as their char-type instantiations but with the prefix basic_. For example, the class template which istream is instantiated from is called basic_istream, the one from which fstream is is called basic_fstream, and so on... The only exception is ios_base, which is by itself type-independent, and therefore is not based on a template, but is a regular class.
Class template instantiations
* The library incorporates two standard sets of instantiations of the entire iostream class template hierarchy: one is narrow-oriented, to manipulate elements of type char and another one, wide-oriented, to manipulate elements of type wchar_t.
* The narrow-oriented (char type) instantiation is probably the better known part of the iostream library. Classes like ios, istream and ofstream are narrow-oriented. The diagram on top of this page shows the names and relationships of narrow-oriented classes.
* The classes of the wide-oriented (wchar_t) instatiation follow the same naming conventions as the narrow-oriented instantiation but with the name of each class and object prefixed with a w character, forming wios, wistream and wofstream, as an example.
Standard objects
* As part of the iostream library, the header file declares certain objects that are used to perform input and output operations on the standard input and output.
* They are divided in two sets: narrow-oriented objects, which are the popular cin, cout, cerr and clog and their wide-oriented counterparts, declared as wcin, wcout, wcerr and wclog.
Types
* The iostream classes barely use fundamental types on their member's prototypes. They generally use defined types that depend on the traits used in their instantiation. For the default char and wchar_t instantiations, types streampos, streamoff and streamsize are used to represent positions, offsets and sizes, respectively.
Manipulators
* Manipulators are global functions designed to be used together with insertion (<<) and extraction (>>) operators performed on iostream stream objects. They generally modify properties and formatting settings of the streams. endl, hex and scientific are some examples of manipulators.
Compatibility notes
The names, prototypes and examples included in this reference for the iostream classes mostly describe and use the char instantiations of the class templates instead of the templates themselves, even though these classes are only one of their possible instantiations. We believe this provides a better readability and is arguably as easy to obtain the names and prototypes of the basic template from the char instantiation as the opposite.
Elements of the iostream library (char instantitation)
Classes: -
ios_base Base class for streams (class )
ios Base class for streams (type-dependent components) (class )
istream Input stream (class )
ostream Output Stream (class )
iostream Input/output stream (class )
ifstream Input file stream class (class )
ofstream Output file stream (class )
fstream Input/output file stream class (class )
istringstream Input string stream (class )
ostringstream Output string stream (class )
stringstream Input/output string stream (class )
streambuf Base buffer class for streams (class )
filebuf File stream buffer (class )
stringbuf String stream buffer (class )
Objects: -
cin Standard input stream (object )
cout Standard output stream (object )
cerr Standard output stream for errors (object )
clog Standard output stream for logging (object )
Types: -
fpos Stream position class template (class template )
steamoff Stream offset type (type )
streampos Stream position type (type )
streamsize Stream size type (type )
Manipulators:
boolalpha Alphanumerical bool values (function )
dec Use decimal base (function )
endl Insert newline and flush (function )
ends Insert null character (function )
fixed Use fixed floating-point notation (function )
flush Flush stream buffer (function )
hex Use hexadecimal base (function )
internal Adjust field by inserting characters at an internal position (function )
left Adjust output to the left (function )
noboolapha No alphanumerical bool values (function )
noshowbase Do not show numerical base prefixes (function )
noshowpoint Do not show decimal point (function )
noshowpos Do not show positive signs (function )
noskipws Do not skip whitespaces (function )
nounitbuf Do not force flushes after insertions (function )
nouppercase Do not generate upper case letters (function )
oct Use octal base (function )
resetiosflags Reset format flags (function )
right Adjust output to the right (function )
scientific Use scientific floating-point notation (function )
setbase Set basefield flag (function )
setfill Set fill character (function )
setiosflags Set format flags (function )
setprecision Set decimal precision (function )
setw Set field width (function )
showbase Show numerical base prefixes (function )
showpoint Show decimal point (function )
showpos Show positive signs (function )
skipws Skip whitespaces (function )
unitbuf Flush buffer after insertions (function )
uppercase Generate upper-case letters (function )
ws Extract whitespaces (function )
Checking state flags
In addition to good, which checks whether the stream is ready for input/output operations, other member functions exist to check for specific states of a stream (all of them return a bool value):
bad(): - Returns true if a reading or writing operation fails. For example, in the case that we try to write to a file that is not open for writing or if the device where we try to write has no space left.
fail(): - Returns true in the same cases as bad(), but also in the case that a format error happens, like when an alphabetical character is extracted when we are trying to read an integer number.
eof(): - Returns true if a file open for reading has reached the end.
good(): - It is the most generic state flag: it returns false in the same cases in which calling any of the previous functions would return true. Note that good and bad are not exact opposites (good checks more state flags at once).
The member function clear() can be used to reset the state flags.
Binary files
For binary files, reading and writing data with the extraction and insertion operators (<< and >>) and functions like getline is not efficient, since we do not need to format any data and data is likely not formatted in lines.
File streams include two member functions specifically designed to read and write binary data sequentially: write and read. The first one (write) is a member function of ostream (inherited by ofstream). And read is a member function of istream (inherited by ifstream). Objects of class fstream have both. Their prototypes are:
write ( memory_block, size );
read ( memory_block, size );
Where memory_block is of type char* (pointer to char), and represents the address of an array of bytes where the read data elements are stored or from where the data elements to be written are taken. The size parameter is an integer value that specifies the number of characters to be read or written from/to the memory block.
Example: -
// reading an entire binary file
#include < iostream >
#include < fstream >
using namespace std;
int main () {
streampos size;
char * memblock;
ifstream file ("example.bin", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "the entire file content is in memory";
delete[] memblock;
}
else cout << "Unable to open file";
return 0;
}
Output: -
the entire file content is in memory
Buffers and Synchronization
When we operate with file streams, these are associated to an internal buffer object of type streambuf. This buffer object may represent a memory block that acts as an intermediary between the stream and the physical file. For example, with an ofstream, each time the member function put (which writes a single character) is called, the character may be inserted in this intermediate buffer instead of being written directly to the physical file with which the stream is associated.
The operating system may also define other layers of buffering for reading and writing to files.
When the buffer is flushed, all the data contained in it is written to the physical medium (if it is an output stream). This process is called synchronization and takes place under any of the following circumstances:
* When the file is closed: before closing a file, all buffers that have not yet been flushed are synchronized and all pending data is written or read to the physical medium.
* When the buffer is full: Buffers have a certain size. When the buffer is full it is automatically synchronized.
* Explicitly, with manipulators: When certain manipulators are used on streams, an explicit synchronization takes place. These manipulators are: flush and endl.
* Explicitly, with member function sync(): Calling the stream's member function sync() causes an immediate synchronization. This function returns an int value equal to -1 if the stream has no associated buffer or in case of failure. Otherwise (if the stream buffer was successfully synchronized) it returns 0.
input output file example
Example 1 : -
#include < iostream >
#include < fstream >
using namespace std;
int main () {
//declare the variable of type ofstream
//since you are dealing with output:
ofstream myfile;
//function to open the file which includes
//the file name:
myfile.open ("example.txt");
//check if the file is open with the is_open()
//function:
if(myfile.is_open()){
//preform the operation(s):
myfile << "Hello world! This is output!" << endl;
//function to close the file:
myfile.close();
}else{
//is_open() returned false and there is a problem:
cout << "Can't open the file!" << endl;
}
return 0;
}
Example 2 : -
// reading a text file
#include < iostream >
#include < fstream >
#include < string >
using namespace std;
int main () {
string line;
//the variable of type ifstream:
ifstream myfile ("example.txt");
//check to see if the file is opened:
if (myfile.is_open())
{ //while there are still lines in the
//file, keep reading:
while (! myfile.eof() )
{ //place the line from myfile into the
//line variable:
getline (myfile,line);
//display the line we gathered:
cout << line << endl;
}
//close the stream:
myfile.close();
}
else cout << "Unable to open file";
return 0;
}


Free Web Hosting